7
$\begingroup$

Problem to solve: Automatically generating 100 animations using the same animation base, just using a different texture every "pass"

I come from the Adobe world, where things like Automate -> batch or Import -> Variable data sets were there to help me with my repetitive flow. Im a bit of a new user when it comes to Blender, but I do love it so far. I'm stuck in a Blender where I just can't wrap my head around and would appreciate your brain power.

I am trying to create multiple animated showcases for our shirts. We have a shirt body object and would like to change the shirt texture for about 100 shirts and export short animations as movies. The animations are about 200 frames in duration, so we are looking at a total of about 20.000 frames rendered, ideally that would result in 100 separate animation movie files.

Visual flow of the process that I have in mind enter image description here I am looking for help on a solution where I could retain my default scene, with all the camera moves, lights and just run either a script, or generate repetitive keyframes with a script, so that each animation can feed of from there. I know that I can replicate this 100 times and define different textures, but its just not developer friendly going forward when we will change the scene and the ambience of it.

So far I've *tried feeding the texture as an image sequence How to automate rendering of the same object with different textures? (but that changed my texture on every frame and still didn't get me closer to a solution. I do see how this would be helpful to have a variable data set approach for still images like in photoshop, but I just can't solve it for an animation? (Maybe a solution here is to somehow change the texture to switch on every 100th frame instead on every frame and somehow and loop the keyframed animation 100 times?)

I've researched a bit on replacing textures with python, however that would entail running the solution on a local computer since the script has to be feed into the command line and blender renderer called multiple times.

Since 20.000 frames is also quite a bit for my setup, ideally the solution would be baked into the blender file so it can be sent off to a render provider for faster results.

Thank you very much for you attention and your help.

$\endgroup$
5
  • 2
    $\begingroup$ There are a few ways to do it. The fastest is perhaps just using the compositor and rendering the UV channels for texture replacement (it's not perfect for complicated materials/lights setups, but just the first render will take its time, while the others will be real fast). With a script it's also fairly simple, but depending if your planning to render in one or in multiple machines, some changes must be taken into account. Could you add some more info about how are you planning to render all (for example, the specs of the render farm you're using)? $\endgroup$ – Secrop Apr 7 at 13:05
  • 1
    $\begingroup$ Thank you @Secrop, I am using garagefarm.net for the renders. I use their RenderBeamer app on OSX and their Blender plugin to initiate the upload. Their support said that by default they do not enable scripts, but can be done with a support ticket. They probably render on multiple machines (they have node based pricing). They do allow for either embedded or relative resources. The UV is a great idea, but we do have some material light, displaces and bumps that unfortunately wouldn't work so well in that case. $\endgroup$ – digitaldestiny Apr 7 at 13:55
  • 1
    $\begingroup$ @digitaldestiny do you want the shirt to rotate a complete 360 in the 100 frames? $\endgroup$ – Aster17 Apr 7 at 13:56
  • $\begingroup$ Yes, there are also some other elements like light moving and changing color. @Aster17 $\endgroup$ – digitaldestiny Apr 7 at 14:07
  • 1
    $\begingroup$ Yes I do understand this and I am trying to make the code. Thanks for the info. $\endgroup$ – Aster17 Apr 7 at 14:08
4
$\begingroup$

check this out:

The script will create one animation for each (.png) file in your Tex_tures folder (you can rename whatever you like). It will create a directory (if it does not exist) for every (.png) file in Text_tures and save the animation in there.

Of course it is not perfect - maybe you should also check whether it is a png file ....but it works.

import bpy
import glob
import os


print ("Script start")

scn = bpy.context.scene

here = bpy.path.abspath('//Tex_tures')

output_path = scn.render.filepath

for eachFile in glob.glob(os.path.join(here, '*.png')):
    print(eachFile)
    fileName = bpy.path.basename(eachFile)
    print(fileName)
    fileNameStart = os.path.splitext(fileName)[0]
#    print("start:", fileNameStart)
    
    bpy.data.images['0063.png'].filepath = eachFile # change this to you texture name
    
    directory = os.path.join(here, fileNameStart)
    print("directory", directory)
    if not os.path.exists(directory):
        os.makedirs(directory)
    scn.render.filepath = os.path.join(directory,"")
    bpy.ops.render.render(animation=True)
    
    
bpy.context.area.ui_type = 'TEXT_EDITOR'

this is the result of my test run with 3 pngs:

enter image description here

$\endgroup$
5
  • $\begingroup$ Thank you @Chris, great effort! So to clarify, this script would run within blender and this part of it here, bpy.data.images['0063.png'] would not keep changing so it can be referred to in every loop? $\endgroup$ – digitaldestiny Apr 7 at 15:22
  • 1
    $\begingroup$ thank you and yes, you should rename it in that way that is is the same name as your texture name in the shader editor. $\endgroup$ – Chris Apr 7 at 15:41
  • 1
    $\begingroup$ if you want i can make a short video tutorial ...how to use it ;) $\endgroup$ – Chris Apr 7 at 15:44
  • $\begingroup$ That is pretty sweet @Chris Let me give it a whirl before you spend any more time, Ill try to get a hang of it and get back to you. Thank you so much for this! $\endgroup$ – digitaldestiny Apr 7 at 16:07
  • $\begingroup$ no problem, you are welcome. I learnt a lot myself ;) $\endgroup$ – Chris Apr 7 at 16:25
5
$\begingroup$

The way I approached this problem in the past, without using Python in Blender, was to create a template .blend file, which uses some texture files it loads, then make a .BAT file which tells blender to render an animation:

"E:\Program Files\Blender Foundation\Blender\blender.exe" -b template.blend -a

Then you can replace the image files using Batch (the language .BAT format uses) with the next setup and render again.

Of course you can also use Python inside Blender:

Change material texture by loading an external .png file with Python

https://docs.blender.org/api/current/bpy.ops.render.html#bpy.ops.render.render

$\endgroup$
4
  • $\begingroup$ That is a good example Markus, it just doesnt solve the approach with rendering on a render farm. If I could render all this on my machine, I agree that passing arguments like so would definitely work. $\endgroup$ – digitaldestiny Apr 7 at 14:25
  • 1
    $\begingroup$ @digitaldestiny I imagine you can't automatically send 100 different setups to your render farm? 🤔 $\endgroup$ – Markus von Broady Apr 7 at 14:35
  • $\begingroup$ Not automatically, but I could do it manually. That is not such a big pain. But then the blender files should at least be automatically replicated and textures in them swapped accordingly. I can live with that solution if you have something in mind. $\endgroup$ – digitaldestiny Apr 7 at 14:46
  • 2
    $\begingroup$ @digitaldestiny as I described, if you point Blender to specific files, then you don't have to touch that template - only copy it to 99 folders, to which you copy different textures with the same names as specified in the template, totaling 100 setups. that is, Blender by default uses relative, not absolute paths $\endgroup$ – Markus von Broady Apr 7 at 14:52
2
$\begingroup$

IMPORTANT SAFETY REMARKS

  • This answer assumes the Python script is ignored on the render farm (which is the case by default) - it is only used on your end to upload multiple files to the render farm. If garagefarm.net enabled autorunning Python scripts for you, you need to disable it for this solution to work correctly - otherwise it may cause errors or even use excessive amount of render credits.
  • Since for convenience this script enables autorunning scripts (to run itself after the garagefarm.net reloads the project which it does every time it is sent to the server) - and having this option enabled is a security vulnerability, it is important that you understand that while this script works, or afterwards if the clean up procedure failed, if you open some malicious .blend file, you may infect your computer. The standard recommendation is to go to Edit > Preferences... > Save & Load and exclude "download" folders from autorunning scripts. After finishing the batch upload to the render farm, also make sure the setting got disabled.

garagefarm.net specific answer using Python

Create a folder with your .blend file and textures. My example: (notice the first texture starts at 1 not 0, as it's 1-based indexing, since that's the convention you use in your question)

Enable auto submit in the renderBeamer.

Add a script to your .blend file, name the script autorun.py:

import bpy, time
time.sleep(1)  # I think the renderBeamer may have problems keeping up without this 

total_renders = 4
filepath_template = 'B:/automatedgarage/base{:04d}.png'
material_name = 'Changing Material'
node_name = 'Image Texture'

thisscript_txtname = 'autorun.py'
currentstep_txtname = 'currentstep'

txt = bpy.data.texts.get(currentstep_txtname)
if txt is None:
    # initialize
    bpy.context.preferences.filepaths.use_scripts_auto_execute = True
    bpy.data.texts[thisscript_txtname].use_module = True
    txt = bpy.data.texts.new(currentstep_txtname)
    txt.write('1')  # 1-based indexing!
    
currentstep = int(txt.as_string())

if currentstep > total_renders:  # 1-based indexing!
    # clean up
    bpy.context.preferences.filepaths.use_scripts_auto_execute = False
    bpy.data.texts[thisscript_txtname].use_module = False
    bpy.data.texts.remove(txt)
    bpy.ops.wm.save_mainfile()
else:
    # prepare render
    nodes = bpy.data.materials[material_name].node_tree.nodes
    image = bpy.data.images.load(filepath = filepath_template.format(currentstep))
    nodes[node_name].image = image
    # if there's more textures, repeat the above 3 lines with different material and node names (and file paths)
    
    txt.lines.data.from_string(str(currentstep + 1))
    bpy.ops.wm.save_mainfile()
    bpy.ops.send.message('INVOKE_DEFAULT')

Change lines 4-7 to reflect your case and run the script. You may need to confirm some messages from the garageFarm plugin.

The files should be automatically uploaded and downloaded (you may need to go to renderBeamer's downloads and press "refresh" to download everything). Then you will get each sequence in a separate folder:

You can't choose a movie file as output in Blender settings, as your render farm doesn't support it. You can, however, after choosing e.g. PNGs, convert the image sequences to movies in the web panel by right-clicking a render and choosing create video sequence. I don't know how to do that in bulk for all results, and I find it irrelevant to Blender really. What would be relevant is how to use Blender to convert those sequences to separate movies.

$\endgroup$
2
  • 1
    $\begingroup$ In my tests the Blender would crash after sending the last project to the renderBeamer. According to the crash log, the error originates in the garageFarm plugin. My guess is that whatever the reason for the plugin to reload the file, might interfere with changing the file by my script. A more stable alternative could be to just swap files and keep the state in a file outside .blend file. $\endgroup$ – Markus von Broady Apr 9 at 7:33
  • $\begingroup$ Thank you, this is definitely a valid approach and I will give it a try with a tweak to submit the files manually 🙌 $\endgroup$ – digitaldestiny Apr 10 at 6:46
1
$\begingroup$

So my idea is a bit crazy, a lot crazy to be honest, but I think this will work. SO it is quite simple. I was planning on doing this. First, take each texture you want and plop them into any video editing software you like that isn't blender. So, now make each image (texture) last as long as you want it to last on the shirt, for ex. 100 frames (4.1666667 seconds if it is a 24 FPS animation). Repeat it for all 100 textures. Then, create a movie file out of it. Now, Go to shading and remove the Principled bsdf and add an Image texture. Set it to a movie and plop in the video file. You might want to change the UV's so they fit. Now, run it and it should probably work. I am not ultra sure if this will work or not, but it most probably will.

Now, you want to render it as that after every 100 frames, the file will be saved as a .mov file, right? Now, please keep an open mind and the absolute answer is no. This is because you want to render it using a render farm, and render farms only render in frames. So my suggestion is this, take each 100 frames and plop them into the video-editing software you love that isn't blender, then render it out as a .mov file and do it for every 100 frames. You can do whatever animations you want and there won't be any problems.

I am not saying any of the code they have provided is wrong or anything, they are great, but the problem is you are sending it to a render farm and because of this you have to change more code and stuff which may lead to more problems, then more code, then more problems, then more... you know the cycle. But using this method does nothing else and will work fine with the render farm and won't cause you problems while animation.

Hope it helps.

$\endgroup$
11
  • $\begingroup$ I like it @Aster17 it is a lot of shoestring and duct tape, but I do think that it is crazy enough to work :D I am a bit concerned with the manual approach and how it is error prone, but I guess that with some love it could :) Thank you for the great thoughts $\endgroup$ – digitaldestiny Apr 7 at 15:19
  • $\begingroup$ Was about to suggest similar re How big are the textures, could you make a 10 x 10 image of all and animate the offsets? but using an image sequence is prob a better idea. $\endgroup$ – batFINGER Apr 7 at 15:21
  • 2
    $\begingroup$ "render farms only render in frames" - I don't know garagefarm.net, but some render farms also render movie files. What's missing in your answer is that you would have to repeat the animations 100 times (increasing the animation length from 100 frames to 10 000 frames), and then set the frame number to #frame // 100. You also have to remember to set in the video editor for each frame to be a keyframe, as well as choose a very high bitrate - I actually considered, just like @batFINGER a single image, but we would have to test which is faster - quality-wise an image is clearly better. $\endgroup$ – Markus von Broady Apr 7 at 15:24
  • 1
    $\begingroup$ @MarkusvonBroady I think you aren't clear, but I have mentioned that the person has to animate each texture for 100 frames and do the same 100 times, and I used it as an example, not what the person has to use. As for the video editor, I specifically mentioned not to use blender's built-in video editor, and something like Windows Moviemaker or something. $\endgroup$ – Aster17 Apr 8 at 2:54
  • 2
    $\begingroup$ Please don't discriminate code :). On average code causes about as many problems as alternatives, as long as your proficiency is similar. I want to make it clear that my comment was meant as complementary information, and not critique. Here's critique: you could prepare an example and describe step-by-step specifically what to do. I'm aware the same critique applies to my answer, I'll try to improve it as soon as I find some time and energy to do that. $\endgroup$ – Markus von Broady Apr 8 at 8:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.