Using two (or more) computers...

Blender's renderer and external renderer export

Moderators: jesterKing, stiv

tds21
Posts: 1
Joined: Tue Dec 03, 2002 3:36 am

Using two (or more) computers...

Post by tds21 »

Is there a way to use a network to render scenes?
Basically a small render farm.
Or is this even worth while with Blender?

bertram
Posts: 0
Joined: Wed Oct 16, 2002 12:03 am

Post by bertram »

I haven't found an out-of-the-box solution yet. And I was searching for this very long and very hard!!! I have even proposed to bring my "farm" to the conference for making possible a session about distributed rendering. Sadly I did not yet receive a clearly positive response :cry:

joeri
Posts: 96
Joined: Fri Jan 10, 2003 6:41 pm
Contact:

Post by joeri »

Network rendering is very much possible with blender.
http://projects.blender.org/projects/networkrender/
But this thing needs a little more work.

Meanwhile blender has a good commandline interface.
try blender /? to see them all.

ideasman
Posts: 0
Joined: Tue Feb 25, 2003 2:37 pm

Post by ideasman »

This works out of the box.

Code: Select all

#!BPY

"""
Name: 'BlenderFarm...'
Blender: 234
Group: 'Export'
Tooltip: 'Blender Render Farm Distributed render.'
"""

#=======================================================#
# Global definitions                                    #
#=======================================================#
 
import Blender
from Blender import *
from Blender.Scene import Render
import os

global ver
ver = '0.4'
global conf

def _mkdir(newdir):
  """works the way a good mkdir should :)
      - already exists, silently complete
      - regular file in the way, raise an exception
      - parent directory(ies) does not exist, make them as well
  """
  if os.path.isdir(newdir):
    pass
  elif sys.exists(newdir):
    raise OSError("a file with the same name as the desired " \
                  "dir, '%s', already exists." % newdir)
  else:
      head, tail = os.path.split(newdir)
      if head and not os.path.isdir(head):
        _mkdir(head)
      #print "_mkdir %s" % repr(newdir)
      if tail:
        os.mkdir(newdir)

def newConf():
	confFile = open(Get("datadir") + 'bfarm.conf', 'w')
	confFile.write('renderdir=none\n')
	confFile.write('tiletimeout=10\n')
	confFile.write('tilecount=4\n')
	confFile.close()


# return a dictionary with the conf.
def getConf(): 
  confFile = Get("datadir") + 'bfarm.conf'
  
  # if there is no config then make a blank one.
  if not sys.exists(confFile):
    newConf()
  
  confFile = open(confFile, 'r')
  conf = {'renderDir':None, 'tileTimeOut':None, 'tileCount':None,}
  
  for l in confFile.readlines():
    splitLine = l.split('=')
    if len(splitLine) >= 2:
      if splitLine[0].lower() == 'renderdir':
        conf['renderDir'] =  splitLine[1].split('\n')[0] #split('/n')[0] to remove the last line 
      elif splitLine[0].lower() == 'tiletimeout':
        conf['tileTimeOut'] = eval(splitLine[1].split('\n')[0])
      elif splitLine[0].lower() == 'tilecount':
        conf['tileCount'] = eval(splitLine[1].split('\n')[0])
  
  return conf


def drawText(text):
  global t
  t = text.split('\n')
  def gui():
    lineHeight = 12
    
    height = len(t) * lineHeight
    BGL.glColor3f(0,0,0)
    for l in t:
      BGL.glRasterPos2i(10, height)
      Draw.Text(l)
      height -= lineHeight
    Draw.Exit()
  Draw.Register(gui)
  Window.Redraw(Window.Types.SCRIPT)


#=======================================================#
# Configure the path... and any other settings          #
#=======================================================#
def configMe():
  global confFile
  # Get existing settings
  conf = getConf()
  
  if conf['renderDir'] == 'none':
    cfgMethod = 1 # Fors
  else:
    cfgMethod = Draw.PupMenu(\
'BlenderFarm Conf...%t|\
Nertwok Path|\
Tile Timeout|\
Number of Tiles|')

  # Esablish defaults if not in config dir
  if conf['renderDir'] != None: renderDirLine = 'renderdir=' + conf['renderDir'] + '\n'
  else: renderDirLine = 'renderdir=' + sys.sep + '\n'
  
  if conf['tileTimeOut'] != None: tileTimeOutLine = 'tiletimeout=' + str(conf['tileTimeOut']) + '\n'
  else: tileTimeOutLine = 'tiletimeout=300\n'
    
  if conf['tileCount'] != None: tileCountLine = 'tilecount=' + str(conf['tileCount']) + '\n'
  else: tileCountLine = 'tilecount=6\n'
  
  confFile = open(Get("datadir") + 'bfarm.conf', 'w')
  if cfgMethod != 1: confFile.write(renderDirLine)
  if cfgMethod != 2: confFile.write(tileTimeOutLine)
  if cfgMethod != 3: confFile.write(tileCountLine)
  
  result = None
  
  if cfgMethod == 1: # Path
    def writePath(path):
      global confFile
      
      # Make SURE there are 
      while path[-1] != sys.sep:
        path = path[:-1]
      
      confFile.write('renderdir=' + path + '\n')
      confFile.close()
    Window.FileSelector(writePath, 'NETWORK PATH', '')
    
  elif cfgMethod == 2:
    while result == None:
      result = Draw.PupIntInput('TimeOut Min', 10, 1, 60)
    confFile.write('tiletimeout=' + str(result) + '\n')
    confFile.close()
  elif cfgMethod == 3: # Tile Count
    while result == None:
      result = Draw.PupIntInput('Divide to # tiles', 6, 2, 100)
    confFile.write('tilecount=' + str(result) + '\n')
    confFile.close()







# Clamp
def max(number):
  if number > 1.0:
    number = 1.0
  return number

#
def randList(list):
  randList = []
  lenList = len(list) 
  while lenList != len(randList):
    randIndex = int( Noise.random() * len(list)  )
    randList.append( list[randIndex] )
    list.remove( list[randIndex] )
  return randList    
  
# Makes a list of rects that setBorder will pass.
def makeBorderList(xparts, yparts):
  borderRectList=[] #We store all the rects here and then return them. 
  xlen = 1.0 / xparts
  ylen = 1.0 / yparts
  xPoint = yPoint = 0.0 # This stores the current X value, and incriments xlen each iteration until its equel to 1.0
  counter = 1 # Inde each border
  while xPoint < 0.999:
    while yPoint < 0.999: # Write the rect to the list
      borderRectList.append( (counter, max(xPoint), max(yPoint), max(xPoint+xlen), max(yPoint+ylen)) )
      counter += 1 # Keep a tag of which index this one is.
      yPoint += ylen
    yPoint = 0.0 # Reset yPoint for the next colum.
    xPoint += xlen
  return borderRectList



#=======================================================#
# General composite function, could be used anywhere    #
# allows us to view all the tiles without any           #
# external libs such as PIL or Imlib, tho it would be   #
# A goog idea if it tried to use these first.           #
#=======================================================#
def composite(imgList, outImage, size):
  oldscene = Scene.GetCurrent()
  scene = Scene.New('BlnederFarm')
  Window.CameraView(1)
  # Setup the render context
  context = scene.getRenderingContext()
  
  xaspect = yaspect = 1
  # we need to set the aspect
  if size[0] == size[1]:
    pass # x and y aspects are the same.
  elif size[0] > size[1]:
    # Width greater then height
    yaspect = size[1] / float(size[0])
  else: # size[0] < size[1]:
    # Height greater then width
    xaspect = size[0] / float(size[1])
  
  context.enableRGBAColor() # Save RGBA 
  context.setImageType(Scene.Render.PNG) # Save RGBA 
  context.enableExtensions(1)
  context.setRenderPath('//' + outImage) # // is the currentdir
  context.partsX(1)
  context.partsY(1)
  # context.setRenderPath("C:/myRenderdir/")
  
  #frame = Blender.Get( 'curframe') 
  context.startFrame(1)
  context.endFrame(1)
  
  context.imageSizeX(size[0])
  context.imageSizeY(size[1])
  
  fIdx = 0 
  while fIdx < len(imgList):
    # Make a new mesh
    ob = Object.New('Mesh')
    scene.link(ob)
  
    me = ob.getData()
    # new material
    mat = Material.New('alphamat')
    mat.mode |= Material.Modes.ZTRANSP
    mat.mode |= Material.Modes.SHADELESS
    mat.setAlpha(0.0)  
    
    
    # Load images or reload images if they are alredy loaded.
    exists = 0
    for i in Image.Get():
      if i.filename == imgList[fIdx]:
        exists = 1
        i.reload()
        image = i
    if exists == 0:
      image = Image.Load(imgList[fIdx])
    
    
    
    # Texture
    tex = Texture.New()
    tex.setType('Image')
    tex.image = image
    tex.imageFlags |= Texture.ImageFlags['USEALPHA']
    
    # Should be faster without these.
    tex.imageFlags &=~Texture.ImageFlags['INTERPOL']
    tex.imageFlags &=~Texture.ImageFlags['MIPMAP']
    
    mat.setTexture(0, tex)
    mtex = mat.getTextures()[0] # we know theres only one.
    mtex.mapto |= Texture.MapTo['ALPHA']
    
    
    me.setMaterials([mat])    
    
    me.verts.append( NMesh.Vert(-xaspect,-yaspect, 0) )
    me.verts.append( NMesh.Vert(-xaspect, yaspect, 0) )
    me.verts.append( NMesh.Vert( xaspect, yaspect, 0) )
    me.verts.append( NMesh.Vert( xaspect,-yaspect, 0) )
    
    f = NMesh.Face()
    f.v.append(me.verts[-1])
    f.v.append(me.verts[-2])
    f.v.append(me.verts[-3])
    f.v.append(me.verts[-4])
    
    f.uv = [(0,0),(1,0),(1,1),(0,1)]
    
    #image = Image.Load(imgList[fIdx])
    #f.image = image
    
    me.faces.append(f)
    fIdx +=1
    me.update()
  
  # Add camera
  ob = Object.New('Camera')
  c = Camera.New('ortho')
  scene.setCurrentCamera(ob)
  
  c.setLens(64)
  c.setClipStart(3)
  c.setClipEnd(5)
  ob.link(c)  
  scene.link(ob)
  ob.setLocation(0,0,4)
  
  scene.update(1)
  
  context.renderAnim()
  
  oldscene.makeCurrent()
  
  # Deleate the scene
  Scene.Unlink(scene)


  

#========================================#
# Gets all number of hoz and vert tiles  #
#========================================#
def getParts(numParts):  
  # Make the number of tiles roughly the same as the real tile count.
  xParts = yParts = 1
  while xParts * yParts < numParts:
    if xParts == yParts:
      xParts += 1
    else:
      yParts += 1
  
  return xParts, yParts

def getPartNumFromFile():
  NUM = '0123456789'
  DEFAULT_TILE_COUNT=4 # px
  
  name = Get('filename').split('.blend')[0]
  
  # Check that there is a number at the end of the filename.
  if name[-1] not in NUM:
    tileCount = DEFAULT_TILE_COUNT
  else:
    # Work out the tile size from the file name.
    tileCount = ''
    while name[-1] in NUM: # Keep pulling in the numbers as long as they are nums.
      tileCount = name[-1] + tileCount
      name = name[0:-1]
    tileCount = eval(tileCount)
    
  return getParts(tileCount)


#=======================================================#
# This function basicly sends the current file to the   #
# render dir and waits for all the tiles to be rendered #
# then it composites it to be viewed.                   #
#=======================================================#
def sendToFarm():
  # Set commonly used path names (local and remote)
  conf = getConf()
  origFileName = Get('filename')       # we'll read from the original
  newFileName = conf['renderDir'] + origFileName.split(sys.sep)[-1]
  # Modify the new file name to include the parts value
  # This is because clients will not have the same settings as you
  # so the filename is an easy place to store it
  newFileName = newFileName.split('.blend')[0] + '_' + str(conf['tileCount']) + '.blend'
  doneName = newFileName.split('.blend')[0] + '.done'
  rendFarmDir = newFileName.split('.blend')[0] # The subdir where tiles are rendered.
  


  
  #=======================================================#
  # Write out a HTML file that updates as the tiles are   #
  # rendered (very cool), This will only work with newer  #
  # browers supporting PNG/Alpha.                         #
  #=======================================================#
  
  #~ def writeHTML():
  #~ '''
#~ <meta http-equiv="refresh" content="2; URL=./template.html">

#~ <DIV ID="layer1" STYLE="position:absolute; top: 0%; left: 0%; 
#~ width: 100%; height: 100%;  z-index: 6"><IMG SRC="./d1_16/d1_160001_0011.png"></DIV>
  #~ '''
  #~ htmlFileName = newFileName.split('.blend')[0] + '.html'
  #~ htmlFile = open(newFileName, 'w')
  #~ htmlFile.write('<HTML>\n')
  #~ htmlFile.write('  <HEAD>\n')
  #~ htmlFile.write('    <title>BlenderFarm '+ origFileName +'</title>\n' )
  #~ htmlFile.write('    <meta http-equiv="refresh" content="2; URL=' + htmlFileName + '">\n' )
  #~ htmlFile.write('  </HEAD>\n')
  #~ htmlFile.write('<BODY bgcolor="#D2D9D2" topmargin=0 marginheight=0 marginwidth=0 leftmargin=0 rightmargin=0>\n')
  
  
  #~ htmlFile.write('  <DIV ID="layer1" STYLE="position:absolute; top: 0%; left: 0%; width: 100%; height: 100%;  z-index: 6">')
  #~ htmlFile.write('    <IMG SRC="./d1_16/d1_160001_0011.png">')
  #~ htmlFile.write('  </DIV>\n') 
  
  
  #~ htmlFile.write('</BODY>\n')
  #~ htmlFile.close()
  
  
  # Save the current blend file on the render
  # directory for all the compuetrs to render.
  # os.remove(newFileName) # Remove first just to be safe
  Save(newFileName, 1)
  
  # Remove any tiles and the .done file.
  try:
    for img in os.listdir(rendFarmDir):
      os.remove(rendFarmDir + '/' + img)
    os.rmdir(rendFarmDir)
  except:
    pass
  # Remove .done file
  try:
    os.remove(doneName)
  except:
    pass
    
  
  # Make the tile rendering dir rendering.
  _mkdir(rendFarmDir)
  

def viewRender():
  # Set commonly used path names (local and remote)
  conf = getConf()
  origFileName = Get('filename')       # we'll read from the original
  newFileName = conf['renderDir'] + origFileName.split(sys.sep)[-1]
  # Modify the new file name to include the parts value
  # This is because clients will not have the same settings as you
  # so the filename is an easy place to store it
  newFileName = newFileName.split('.blend')[0] + '_' + str(conf['tileCount']) + '.blend'
  doneName = newFileName.split('.blend')[0] + '.done'
  rendFarmDir = newFileName.split('.blend')[0] # The subdir where tiles are rendered.
  
  
  
  # We can use this to draw a percentage status.
  xparts, yparts = getParts(conf['tileCount'])
  tileCount = xparts * yparts
  
  # Make sure all the images are rendered (non empty, no placeholders)
  allrendered = 0
  while allrendered == 0:
    imageList = os.listdir(rendFarmDir)
    
    text = 'BlenderFarm v'+str(ver) + ' rendering '+newFileName
    text += '(' + ( (len(imageList)) * '#' + (tileCount - len(imageList) ) * '_' ) + ')\n'
    drawText(text)
    
    
    # Draw how many tiles have been rendered.
    #Window.DrawProgressBar (tileCount / (len(imageList)+0.001), newFileName) 
    
    
    sys.sleep(100)
    if sys.exists(doneName) == 1:
      allrendered = 1
      for img in imageList:
        if os.path.getsize(rendFarmDir + '/' + img) == 0:
          allrendered = 0
          break
  
  # Generate a list of images to send to the composite func.
  imageList = []
  for img in os.listdir(rendFarmDir):  
    imageList.append(rendFarmDir + '/' + img)
  
  # 
  scene = Scene.GetCurrent()
  context = scene.getRenderingContext()
  width = context.imageSizeX()
  height = context.imageSizeY()
  composite(imageList, newFileName.split('.blend')[0], ( width , height ))  

  
#=======================================================#
# start a loop where we look for files to render.       #
# in the render dir, if we find any, render a rendom    #
# selection of tiles.                                   # 
#=======================================================#
def renderSlave():
  print 'BlenderFarm Client ', ver, 'started.'
  print 'Press Ctrl+Alt+Shift to exit'
  import Blender
  Blender.Window.WaitCursor(1)
  while 1:
    #=======================================================#
    # Chech if the user presses escape, if so. quit being   #
    # a render client. and to back to your normal blending  #
    #=======================================================#

    import Blender
    from Blender import Scene, Get, Noise, Load, sys, BGL, Draw, Window
    from Blender.Scene import Render
    import os
    from blenderfarm import getConf
    
    
    if Window.GetKeyQualifiers() & Window.Qual.CTRL:
      if Window.GetKeyQualifiers() & Window.Qual.ALT:
        if Window.GetKeyQualifiers() & Window.Qual.SHIFT:
          break
      
    conf = getConf()
    for file_blend in os.listdir(conf['renderDir']):
      
      if Window.GetKeyQualifiers() & Window.Qual.CTRL:
        if Window.GetKeyQualifiers() & Window.Qual.ALT:
          if Window.GetKeyQualifiers() & Window.Qual.SHIFT:
            break
      
      if file_blend[-6:] == '.blend':
        # We have a blend file, now if we cant find an image, render it.
        done = 0
        
        for file_done in os.listdir(conf['renderDir']):
          if Window.GetKeyQualifiers() & Window.Qual.CTRL:
            if Window.GetKeyQualifiers() & Window.Qual.ALT:
              if Window.GetKeyQualifiers() & Window.Qual.SHIFT:
                break
                
          if file_done == file_blend.split('.blend')[0] + '.done':
            done = 1
            break
        # Not rendered, so do so.
        if done == 0:
          #===================================================
          Load(conf['renderDir']+file_blend) # BUGGERS UP EVERYTHING, RESETS ALL FUNCTS/VARS
          from Blender import Scene, Get, Noise, Load, sys
          from Blender.Scene import Render
          import os
          file_blend = Get('filename')
          
          from blenderfarm import getConf, getParts, getPartNumFromFile, drawText, max, randList, makeBorderList
          
          conf = getConf()
          
          print 'Rendering: ', file_blend
          xParts, yParts = getPartNumFromFile()
          randBorderList = randList( makeBorderList(xParts,yParts) )
          
          # SETS UP DEFAULTS NEEDED FOR OUTPUTTING AN IMAGE THAT CAN BE COMPOSITED.
          Render.EnableDispView()
          scn = Scene.GetCurrent()
          context = scn.getRenderingContext()
          context.enableBorderRender(1)
          context.enableRGBAColor() # Save RGBA
          context.setImageType(Render.PNG) # Save RGBA
          context.enableExtensions(1)
          
          # Make image name,  Remove .blend
          renderName = file_blend.split('.blend')[0] + '_' # frameNum.png will be added.
          
          # Add the extra directory
          name = sys.basename(file_blend.split('.blend')[0])
          dir = sys.dirname(file_blend)
          
          renderName = dir + sys.sep + name + sys.sep + name
          
          # Set the start and end frame to the current frame.
          curFrame = Get( 'curframe')
          context.startFrame(curFrame)
          context.endFrame(curFrame)
          
          # Keep track of frames rendered, only for a report.
          renderedFrames = 0
          
          for border in randBorderList:
            # Set the new file name WITH X/Y parts
            # blendfilename_partnum_framenum.ext
            # eg. render_01_0001.png
            partNum = str(border[0])
            while len(partNum) < 4:
              partNum = '0' + partNum
            uniqueRenderName = renderName + partNum + '_' # We add 1 so that the first image is 1, not 0
            
            # CREATE THE REAL NAME OF THE OYTPUT FILE
            frameNum = str(curFrame)
            while len(frameNum) < 4:
              frameNum = '0' + frameNum
            # Pre epmt the image name.
            fileToRender = uniqueRenderName + frameNum + '.png'
            
            # Chech that the file isnt alredy there
            if sys.exists(fileToRender) == 0:
              #Create a dummy file so no other nodes try to render the image.
              file = open(fileToRender,"w").close()
              
              # SET RENDER NAME AND PATH.
              context.setRenderPath(uniqueRenderName)
              context.setBorder(border[1], border[2], border[3], border[4] )  
              context.renderAnim() # This saves the pics.
              
              renderedFrames += 1
          # touch the done file
          open(file_blend[:file_blend.index('.')] + '.done', 'w').close()
          print 'Done:', file_blend
      sys.sleep(100)
    sys.sleep(100)
  # END renderSlave
  Window.WaitCursor(0)
  

#=======================================================#
# Ask the user weather they want to start a client or   #
# send the existing scene to the renderfarm             #
#=======================================================#
method = Draw.PupMenu(\
'BlenderFarm...%t|\
Send Scene|\
Send & Render|\
View Rendered Tiles|\
Render Watch (Slave)|\
Configure this Node|')

# Launch the function based on the menu choice.
if method == 1: # Render current scene.
  sendToFarm()
if method == 2: # Send & Render & View
  sendToFarm()
  renderSlave()
if method == 3: # View rendered tiles
  viewRender()
elif method == 4: # Render cleint.
  renderSlave()
elif method == 5: # configure.
  configMe()

JWalton
Posts: 58
Joined: Sun Oct 13, 2002 7:39 pm
Contact:

Post by JWalton »

nice, but yuck:

#=======================================================#
# Write out a HTML file that updates as the tiles are #
# rendered (very cool), This will only work with newer #
# browers supporting PNG/Alpha. #
#=======================================================#

ideasman
Posts: 0
Joined: Tue Feb 25, 2003 2:37 pm

Post by ideasman »

Why Yuck? Its not implimented yet and its optional anyway-

Its just nice to have a continual updating display of rendered tiles.
- Cam

matt_e
Posts: 410
Joined: Mon Oct 14, 2002 4:32 am
Location: Sydney, Australia
Contact:

Post by matt_e »

No, you need to make a special JWalton version that sends the images as ASCII art when you telnet to port 80 ;)

joeri
Posts: 96
Joined: Fri Jan 10, 2003 6:41 pm
Contact:

Post by joeri »

Small crit:
Does the python script need a full installation of python?
If so, it's not out of the box.

ideasman
Posts: 0
Joined: Tue Feb 25, 2003 2:37 pm

Post by ideasman »

joeri wrote:Small crit:
Does the python script need a full installation of python?
If so, it's not out of the box.
Fair comment, It uses the OS module only.

Though I was looking at Blender.sys and all that stops me from using it instead of os- Is a MakeDir function.

- Still the script works well for me- can be configured via menu's and manages to render a single image over many PC's.

This is the first script for blender that does this. Areas its lacking in are mostly todo with blenders inability to composite images and various other things from python.

steve_t
Posts: 30
Joined: Tue Nov 05, 2002 7:10 am

Post by steve_t »

I LOOVE ideasman's script... however most of the time when I need to pull together that much power I am doing an animation.

We... o9studios just finished a comercial project that involved rendering a few animations that totaled to be about 2800 frames. Because of the need for realism and to achieve that specific look the rendertime was about 10 minutes a frame. We ended up rendering on 5 computers arround the clock for four days. The time and sress that it takes to do this manually and do it right is crazy.

Here are some features that would save me time and headaches... probably not at all fesable through python

-distributing blends and chunks of frames to multiple clients both locally and over the internet
-making sure the same version or build is being used on all nodes
-saving and naming frames in a consistent way
-harvesting and grouping frames in a central location
-getting realtime statis about all the nodes and the animations being rendered
-distributed backup of frames to anticipate for hardware and link failure
-dynamic reallocation of frames in the event a node is removed or added to the farm.
-the ability to handel multiple jobs with different priorities
-the ability to allert me by email when things finish or when things are not going as planned.
-when one server stops comunicating have another node start being the server and continue the render.

just getting some crazy ideas out there...

Thanks again idasman... your script rocks!

-steve

ideasman
Posts: 0
Joined: Tue Feb 25, 2003 2:37 pm

Post by ideasman »

Hi, your assertions are good- An animation based render farm needs to be created. preferably one that uses blender out of the box. - with no external python modules.

(makeing a directory needs to be added to Blender.sys- mabe have it in by 2.35)

I actually wrote my renderer to do still images because it was more of a challange then simply splitting frames between PC's- I intend to adapt my script to do both but Im busy since Ill be taking some time off for bconf.

Anyhow- The problem is that Im not the right person to code this- Mainly because I never ever render anything since my work is strictly realtime models.- Why dont you hire a coder to write a animation based renderfarm, or do it yourself?.

I find if your using code you write, it tends to be easy to test it and add small features where needed. - A coder testing his own code and never using it dosent get the same quality of testing.

bertram
Posts: 0
Joined: Wed Oct 16, 2002 12:03 am

Post by bertram »

Thanks ideasman, I've already noticed your script some time ago but decided, that tiling each frame would be contraproductive since the setup of the scenefile would have to be done for each tile which again would blow up the overall render time.

The 'renderd' / 'broker'-solution was a very good approach, but apparently it doesn't work with the current version of blender.
Isn't there anybody working on the renderdaemon no more? Why has this really good piece of code been dropped?

joeri
Posts: 96
Joined: Fri Jan 10, 2003 6:41 pm
Contact:

Post by joeri »

I'd like to add some points to steve_t list.

- Scheduler. I'd like to render on all the machines in my company, but not
during the day when people are working on them.
- Pause / Play. Pause will pause blender for 10 minutes. Play will ignore schedule setting.
- Finish / Quit difference. Finish will stop the rendering after finishing the current task, Quit will stop now.
- Benchmarker. I think machines need to render chunks of tasks, not single images.
This can often be faster (specialy over the internet) file rendering should be slower then file (blender/textures/images) transport.
The benchmarker should determen the size of the chunks.
- Ready predictor. So how long do I have to wait for this task to finish?
- Dependicies. Sequence rendering can only be done if all needed frames are ready. So a "Do only if task #x is ready" button comes in handy.
- Blender dispatcher. Install the correct version of blender on local machine (Maybe this is in steve's list)
- File Reject. Some files are so intensive they should only be renderd on machines with lots of memory. The local deamon should decline tasks it 'cannot' render. Also files that give errors on local machine but are file on others, forget them (low prio for this machine)
- Online status report. The interface might be html, so I can view online how things are going.

Not sure what the 'correct name' is about. It should use the name in the blender file. On the location in the blender file.
If you're on windows map a network drive to R: (net use R: \\imageMachine\RenderRoot\ ) and let all machines render to R:
If you are on Linux just render to a NFS mounted /Render ?
With backup if that machine drops out or has no harddisk space left.


Hee, does not need to be finisched by tomorrow, but next week would be great ;)

ideasman
Posts: 0
Joined: Tue Feb 25, 2003 2:37 pm

Post by ideasman »

bertram wrote:Thanks ideasman, I've already noticed your script some time ago but decided, that tiling each frame would be contraproductive since the setup of the scenefile would have to be done for each tile which again would blow up the overall render time.

The 'renderd' / 'broker'-solution was a very good approach, but apparently it doesn't work with the current version of blender.
Isn't there anybody working on the renderdaemon no more? Why has this really good piece of code been dropped?
Tiling is only good for a single image-

Some images can take days to render (poster size for eg) and in these cases the time for generating render data is neglidgable.

Imagine your working on a raytraced scene with 600'000 polys- You want a preview render, even at low quality- splitting into tiles would be an improvment, even if just for your workflow.

But your right- for an animation, rendering tiles would be stupid.

steve_t
Posts: 30
Joined: Tue Nov 05, 2002 7:10 am

Post by steve_t »

When breaking up the image into tiles is useful is when you are modeling and tweaking in a large scene. If you have your render farm sitting dormant while you are working why not have all or some of them render previews while you keep blending.

What would be perfect is a system that did both. You could use the frame splitter for stills and previews allong side a version geared twards animation.

I am not a great python coder but I don't think it would be too hard to make a script to manage animation renders over a lan and to have it generate html or php for statistics and farm management. If I have some extra time I might take a shot at it.

-steve

Post Reply