26 January, 2020

Blender Python Tutorial: How to create an Add-on - The Shader Library [bpy]




In this video, we will be creating an add-on for the Shader Node Editor called the Shader Library. 

This Add-on was created for this tutorial and is not meant to be anything other than to demonstrate how it's possible but if you want to download the script you can download it here

If you guys like it, I could look at developing it further but keep in mind that there are probably better Add-ons like this already!. 


Using the knowledge from the previous videos and utilizing the template scripts, we can quickly create a Main Panel and add some bl_info, (Remember without the bl_info we can not install our add-on from file)

In the previous videos, we have been using Operations that are readily available, though in this example there are no functions that will create the Shaders that we want. 

We have to create a custom Operator and then define (with python) what nodes we want to add to our Shader. We also need to then connect (or link as it's actually known) the nodes together.

I find it a good idea to add and arrange the nodes in a separate window as I write the code. It helps me keep track of what nodes I have added and it also lets me see how I need to link the nodes. 


Alternatively, I would suggest writing down the Nodes you want to use before hand. 


 If you find moving the Nodes around pain, this may help. 





The .location parameter will move your node anywhere you want but knowing which set of numbers will move it, Horizontally or Vertically is a bit of trial and error at first.

(-200, -90) - The numbers on the left will move the node to the Left or Right. The numbers on the right will move the node Up or Down.

So if we imagine that the center of the screen 0, if we want to move the Emission node to the Left we would type (-200,0). If we want the Node to move to the right we would type (200,0)

Using that logic, to move up would be (0,200), and down would be (0.-200). 


For this Example, I start by creating a Diamond Shader. It doesn't matter what kind of Shader you want to create, the process is always the same.
 

We first create a Material and call it Diamond. Then we add the nodes that are required. 

  

Once we have finished writing our custom Operator, we need to make sure we register and unregister all classes and then add the button (on the Main Panel) to call the custom operator. 

Adding new Shaders becomes much easier since we can use the first Custom Operator as a template. We can copy and paste most of the code we have just written and then go through and change the appropriate details.

I decided to add a few Shaders that I thought were interesting and there are hundreds of  different Shaders we could create.

Think we should add a specific Shader?. Let us know in the comments..

The Metallic Shaders are really basic. Though if you play around with some of the settings you can get some nice looking results. I would also make sure to follow your normal PBR Process when creating Gold, Silver, Copper ect


I wanted this add-on to take out some of the hassle and speed up our workflow.

I hope you guys find this video helpful and as always, thanks for Reading!
.

17 January, 2020

Scripting Continued - Blender Python - bpy



In this video, we will be continuing scripting our "Object Adder" Add-on.

We will add some more functions such as the Smooth Shading option, Add a Modifier and more.

We also look at creating two more panels (for simplicity we call them Panel A and Panel B). After creating the new Panels we can add them to the Main Panel as "Sub Panels". 





It's really easy to add a panel to another panel and it only requires one property. By adding the, bl_parent_id = 'PT_MainPanel' 
we are telling 'Panel A' to be a child of the Main Panel.



By adding the, bl_options = {'DEFAULT_CLOSED'} 
we are telling the Panel to be minimized by default. If you have a whole bunch of panels open by default it can be a pain for the user to navigate to the section they intend to use.




 Once we are happy with the Add-on we need to make sure we add the bl-info at the beginning of the script (you can see the full script below). 

Without this Information, we can not install the Add-on. 







With our add-on now installed, we can use it without needing to run the script nor mess around with any settings.


  

Of course this Add-on is super simple and we can always add, change and improve this add-on but I wanted to create something easy to follow and I hope I have managed to inspire you to take this further and start to make awesome add-ons!..

If you want to use this script you can copy and paste the text below or you can click here.

In the Next Tutorial, we will be creating an Add-on that's a little more advanced but with the knowledge we have learned over the last two videos, it should be easier to pick up.

Again, I hope you found this Tutorial helpful! be sure to let us know what you think of this series or if you want more videos like this? 



Script result : 

__________________________________________________________________________
 


bl_info = {
    "name": "Object Adder",
    "author": "Darkfall",
    "version": (1, 0),
    "blender": (2, 80, 0),
    "location": "View3D > Toolbar > Object Adder",
    "description": "Adds objects and other functions to help our workflow (Tutorial Result)",
    "warning": "",
    "wiki_url": "",
    "category": "Add Mesh",
}

import bpy

    #This is the Main Panel (Parent of Panel A and B)
class MainPanel(bpy.types.Panel):
    bl_label = "Object Adder"
    bl_idname = "PT_MainPanel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Object Adder'
   
    def draw(self, context):
        layout = self.layout
        layout.scale_y = 1.2
       
        row = layout.row()
        row.label(text= "Add an object", icon= 'OBJECT_ORIGIN')
        row = layout.row()
        row.operator("mesh.primitive_cube_add", icon= 'CUBE', text= "Cube")
        row.operator("mesh.primitive_uv_sphere_add", icon= 'SPHERE', text= "Sphere")
        row.operator("mesh.primitive_monkey_add", icon= 'MESH_MONKEY', text= "Suzanne")
        row = layout.row()
        row.operator("curve.primitive_bezier_curve_add", icon= 'CURVE_BEZCURVE', text= "Bezier Curve")
        row.operator("curve.primitive_bezier_circle_add", icon= 'CURVE_BEZCIRCLE', text= "Bezier Circle")
       
       
        row = layout.row()
        row.operator("object.text_add", icon= 'FILE_FONT', text= "Add Font")
        row = layout.row()
       


    #This is Panel A - The Scale Sub Panel (Child of MainPanel)
class PanelA(bpy.types.Panel):
    bl_label = "Scale"
    bl_idname = "PT_PanelA"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Object Adder'
    bl_parent_id = 'PT_MainPanel'
    bl_options = {'DEFAULT_CLOSED'}
   
    def draw(self, context):
        layout = self.layout
        obj = context.object
       
        row = layout.row()
        row.label(text= "Select an option to scale your", icon= 'FONT_DATA')
        row = layout.row()
        row.label(text= "      object.")
        row = layout.row()
        row.operator("transform.resize")
        row = layout.row()
        layout.scale_y = 1.2
       
        col = layout.column()
        col.prop(obj, "scale")
       


    #This is Panel B - The Specials Sub Panel (Child of MainPanel)
class PanelB(bpy.types.Panel):
    bl_label = "Specials"
    bl_idname = "PT_PanelB"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Object Adder'
    bl_parent_id = 'PT_MainPanel'
    bl_options = {'DEFAULT_CLOSED'}
   
    def draw(self, context):
        layout = self.layout
       
        row = layout.row()
        row.label(text= "Select a Special Option", icon= 'COLOR_BLUE')
        row = layout.row()
        row.operator("object.shade_smooth", icon= 'MOD_SMOOTH', text= "Set Smooth Shading")
        row.operator("object.subdivision_set", icon= 'MOD_SUBSURF', text= "Add Subsurf")
        row = layout.row()
        row.operator("object.modifier_add", icon= 'MODIFIER')
       
  
       
    #Here we are Registering the Classes       
def register():
    bpy.utils.register_class(MainPanel)
    bpy.utils.register_class(PanelA)
    bpy.utils.register_class(PanelB)

    #Here we are UnRegistering the Classes   
def unregister():
    bpy.utils.unregister_class(MainPanel)
    bpy.utils.unregister_class(PanelA)
    bpy.utils.unregister_class(PanelB)

    #This is required in order for the script to run in the text editor   
if __name__ == "__main__":
    register() 
                         






12 January, 2020

An Introduction to Scripting (Blender Python - bpy)




In this video,we will be taking a look at Scripting with Blender and Python.

Before we begin, I should mention that I am in no way an expert and in fact, I have only been learning Python (and scripting in general) for a short time. That being said, I went from knowing absolutely nothing - to developing the Darkfall VFX Nodes Add-on, and would like to share with you some tips and maybe a basic introduction into Scripting. 




  We first start by arranging our layout. There are three important windows we need in order to start scripting and they can be placed anywhere in your layout. It's a good idea to save a template file (so you can use a fresh scripting start up file each time). 

Learning Python and Scripting may seem daunting at first but with a little time and patience you can create something useful. 


If you do get stuck and need some help you can always check out the Blender API, there's a stockpile of really useful information along with some nice examples. You can also check out The Blender Stack Exchange, I have been saved many times by helpful people over at the Stack Exchange and certainly recommend using it. 






Blender also comes with many Python Templates for you to check out. I find it a good idea to have a look at how other scripts are structured and many times they can be slightly adapted to fit our needs.

Now, I assume that anyone reading this blog post will have their own idea for an add-on and many things in this introduction may not apply to what you need but I think having a basic understanding of creating a simple script will go a long way when it comes to tackling your own idea. 



In this Introduction, we will be creating a very simple add-on that I dubbed the "Object Adder"... With just a few lines of code we have created our first add-on!. Congratulations!.. 







We created a Panel in the 3D View that has a bunch of buttons, that when pressed add objects. So yeah, it's obviously not that impressive but if (like me) you thought you wouldn't ever be able to code something, you have just made your first steps into the new world of Python.



There are some different ways we can layout the panel and making it look "pretty" can always come later. I like to make sure everything is working and then we can go back and make some adjustments. The first version of the Darkfall VFX Nodes add-on was a mess. Not only did it look bad but it also was not as simple to use as it is now. 

Thanks to those who have downloaded and used the Add-on, I took their feedback and started to develop newer versions. So with that being said, If you find yourself stuck or need help improving your add-on, be sure to take all the feedback you can get. 

Since we could not cover everything in a single Video, I will be creating more videos on scripting and hopefully you guys will find them helpful. If you have any suggestions on what you want to see, make sure you leave a comment in the video and let us know!.

If you guys want to check out the code that we wrote in the video, you can find it here:


import bpy

class TestPanel(bpy.types.Panel):
    bl_label = "Object Adder"
    bl_idname = "PT_TestPanel"
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'My 1st Addon'
   
    def draw(self, context):
        layout = self.layout
       
        row = layout.row()
        row.label(text= "Add an object", icon= 'OBJECT_ORIGIN')
        row = layout.row()
        row.operator("mesh.primitive_cube_add", icon= 'CUBE')
       
        row.operator("mesh.primitive_uv_sphere_add", icon= 'SPHERE')
        row = layout.row()
        row.operator("object.text_add", icon= 'FILE_FONT', text= "Font Button")
       
       
       
       
def register():
    bpy.utils.register_class(TestPanel)
   
def unregister():
    bpy.utils.unregister_class(TestPanel)
   
if __name__ == "__main__":
    register()