From 6ada248fb8b1b17a25c9e23a9a36062756fdbe30 Mon Sep 17 00:00:00 2001 From: Justin Date: Fri, 16 Mar 2018 09:28:06 -0600 Subject: [PATCH] Multiple materials (#12) * Added support for per-frame material * Fixed Bake Sequence for single-material sequences * Start frame, playback speed, frame mode only show after sequence loaded * Updated README Closes #10 --- README.md | 16 ++++---- mesh_sequence_controller.py | 78 ++++++++++++++++++++++--------------- 2 files changed, 55 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 4e11c67..59be8fd 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Stop-motion-OBJ A Blender add-on for importing a sequence of meshes as frames -Stop motion OBJ allows you to import a sequence of OBJ (or STL or PLY) files and render them as individual frames. Have a RealFlow animation but want to render it in Blender? This addon is for you! Currently tested for Blender 2.77.1. +Stop motion OBJ allows you to import a sequence of OBJ (or STL or PLY) files and render them as individual frames. Have a RealFlow animation but want to render it in Blender? This addon is for you! Currently tested for Blender 2.79.1. If you find this add-on helpful, please consider donating to support development: @@ -22,9 +22,10 @@ PayPal: https://www.paypal.me/justinj - Supports shapes with UVs and image textures - Variable playback speed - Multiple playback modes -- Object can have materials +- Object can have different materials on each frame + - For instance, you can have a different MTL file for each OBJ file - Bake sequence - - This allows the sequence to be seen on other computers without installing the addon (in a renderfarm, for example) + - This allows the sequence to be viewed on other computers without installing the addon (in a renderfarm, for example) ### Limitations - Only absolute filepaths are supported (for now) @@ -37,7 +38,7 @@ PayPal: https://www.paypal.me/justinj - Sequences can now be duplicated, but they share a material. For a duplicate sequence with a different material, you have to re-import the sequence. ## Installing Stop motion OBJ -- Download mesh_sequence_controller.py and move it to Blender's addons folder (something like C:\Program Files\Blender Foundation\Blender\2.77\scripts\addons) +- Download mesh_sequence_controller.py and move it to Blender's addons folder (something like C:\Program Files\Blender Foundation\Blender\2.79\scripts\addons) - Open Blender and open the Add-ons preferences (File > User Preferences... > Add-ons) - In the search bar, type 'OBJ' and look for the Stop motion OBJ addon in the list - Check the box to install it, and click 'Save User Settings' @@ -52,15 +53,16 @@ PayPal: https://www.paypal.me/justinj - Enter the Root Folder by clicking on the folder button and navigating to the folder where the mesh files are stored. **Make sure to UNCHECK ‘Relative Path’** - In the File Name box, enter a common prefix of the files. - ex: If you have frame001, frame002, frame003, you could enter ‘frame’, 'fram', or even 'f' +- If your sequence has a different material for each frame, check the "Material per Frame" checkbox. Otherwise, leave it unchecked. - Click ‘Load Mesh Sequence’ to load. - Depending on the number of frames, this could take a while. - Step through a few frames to see the animation. - You can adjust which frame the animation starts on as well as its playback speed. - You can also decide what happens before and after the mesh sequence: - - 'Blank' will simply make the object disappear + - 'Blank' will simply make the object disappear after the end of the sequence - 'Extend' will freeze the first and last frames before and after the mesh sequence, respectively - 'Repeat' will repeat the animation - 'Bounce' will play the animation in reverse once the sequence has finished - Once your sequence is loaded, you can change the shading (smooth or flat) of the entire sequence: - - The shading buttons are found in the Mesh Sequence Settings for the object. - - Note: The normal shading buttons (in the 3D View "Tools" panel) will only affect the current frame, not the entire sequence. + - The shading buttons are found in the Mesh Sequence Settings for the object + - Note: The normal shading buttons (in the 3D View "Tools" panel) will only affect the current frame, not the entire sequence diff --git a/mesh_sequence_controller.py b/mesh_sequence_controller.py index 0a821fd..a1e8bdb 100644 --- a/mesh_sequence_controller.py +++ b/mesh_sequence_controller.py @@ -1,7 +1,7 @@ # ##### BEGIN GPL LICENSE BLOCK ##### # # Stop motion OBJ: A Mesh sequence importer for Blender -# Copyright (C) 2016-2017 Justin Jensen +# Copyright (C) 2016-2018 Justin Jensen # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -23,8 +23,8 @@ "name" : "Stop motion OBJ", "description": "Import a sequence of OBJ (or STL or PLY) files and display them each as a single frame of animation. This add-on also supports the .STL and .PLY file formats.", "author": "Justin Jensen", - "version": (0, 1), - "blender": (2, 78, 0), + "version": (0, 2), + "blender": (2, 79, 0), "location": "View 3D > Add > Mesh > Mesh Sequence", "warning": "", "category": "Add Mesh", @@ -82,6 +82,12 @@ class MeshSequenceSettings(bpy.types.PropertyGroup): name='Frame Mode', default='1') + #material mode (one material total or one material per frame) + perFrameMaterial = bpy.props.BoolProperty( + name='Material per Frame', + default=False + ) + #playback speed speed = bpy.props.FloatProperty( name='Playback Speed', @@ -276,11 +282,13 @@ def setFrameObj(self, _obj, _frameNum): prev_mesh = _obj.data #swap the meshes _obj.data = self.getMesh(_obj, idx) - #if the previous mesh had a material, copy it to the new one - if(len(prev_mesh.materials) > 0): - prev_material = prev_mesh.materials[0] - _obj.data.materials.clear() - _obj.data.materials.append(prev_material) + # If this object doesn't have materials for each frame + if(_obj.mesh_sequence_settings.perFrameMaterial == False): + #if the previous mesh had a material, copy it to the new one + if(len(prev_mesh.materials) > 0): + prev_material = prev_mesh.materials[0] + _obj.data.materials.clear() + _obj.data.materials.append(prev_material) #iterate over the meshes in the sequence and set their shading to smooth or flat def shadeSequence(self, _obj, _smooth): @@ -335,8 +343,6 @@ def bakeSequence(self, _obj): #create a dictionary mapping meshes to new objects, meshToObject meshToObject = {} - #create a placeholder for the object's material, objMaterial - objMaterial = None meshNames = _obj.mesh_sequence_settings.meshNames.split('/') #for each mesh (including the empty mesh): @@ -349,9 +355,6 @@ def bakeSequence(self, _obj): scn.objects.link(tmpObj) #remove the fake user from the mesh mesh.use_fake_user = False - #if the mesh has a material, store this in objMaterial - if(len(mesh.materials) > 0): - objMaterial = mesh.materials[0] #add a dictionary entry to meshToObject, the mesh => the object meshToObject[mesh] = tmpObj #in the object, add keyframes at frames 0 and the last frame of the animation: @@ -366,14 +369,21 @@ def bakeSequence(self, _obj): #set the empty object as this object's parent tmpObj.parent = containerObj - #if objMaterial was set: - if(objMaterial != None): + #If this is a single-material sequence, make sure the material is copied to the whole sequence + #This assumes that the first mesh in the sequence has a material + if(_obj.mesh_sequence_settings.perFrameMaterial == False): + #grab the materials from the first frame + objMaterials = bpy.data.meshes[meshNames[1]].materials #for each mesh: - for meshName in meshNames: + iterMeshes = iter(meshNames) + next(iterMeshes) #skip the emptyMesh + next(iterMeshes) #skip the first mesh (we'll copy the material from this one into the rest of them) + for meshName in iterMeshes: mesh = bpy.data.meshes[meshName] #set the material to objMaterial mesh.materials.clear() - mesh.materials.append(objMaterial) + for material in objMaterials: + mesh.materials.append(material) #for each frame of the animation: for frameNum in range(scn.frame_start, scn.frame_end + 1): @@ -541,31 +551,35 @@ def draw(self, context): row = layout.row() row.prop(objSettings, "fileFormat") + #material mode (one material total or one material per frame) + row = layout.row() + row.prop(objSettings, "perFrameMaterial") + #button for loading row = layout.row() row.operator("ms.load_mesh_sequence") - #start frame - row = layout.row() - row.prop(objSettings, "startFrame") - - #frame mode - row = layout.row() - row.prop(objSettings, "frameMode") - - #playback speed - row = layout.row() - row.prop(objSettings, "speed") - - #Show the shading buttons only if a sequence has been loaded if(objSettings.loaded == True): + #start frame + row = layout.row() + row.prop(objSettings, "startFrame") + + #frame mode + row = layout.row() + row.prop(objSettings, "frameMode") + + #playback speed + row = layout.row() + row.prop(objSettings, "speed") + + #Show the shading buttons only if a sequence has been loaded layout.row().separator() row = layout.row(align=True) row.label("Shading:") row.operator("ms.batch_shade_smooth") row.operator("ms.batch_shade_flat") - #Show the Bake Sequence button only if a sequence has been loaded - if(objSettings.loaded == True): + + #Bake Sequence button layout.row().separator() row = layout.row() box = row.box()