Blenderのシェーダーでオブジェクトの座標を出力するノードを作成

Blenderのシェーダーでは特定のオブジェクトの座標を取得するノードが用意されていません
似たようなノードに、オブジェクトからの座標を出力するノードはありますが
ターゲットのオブジェクトを回転させてしまうと欲しい動作とは違ってきてしまいます。
![212031202.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/7a921cf6-0158-1025-754e-3899040b5444.gif)
Blenderにはドライバという　他のオブジェクトの情報から動的に値を設定する機能があって
ノードの値の入力にもドライバを設定することができるので
面倒な設定を自動化するアドオンを作成してみました

```PY:y_add_LocationNode.py
bl_info = {
    "name" : "Add location node",
    "author" : "Yukimituki",
    "description" : "",
    "blender" : (2, 80, 0),
    "version" : (0, 0, 1),
    "location" : "",
    "warning" : "",
    "category" : "Node"
}
import bpy
class NodeLocationNoePanel(bpy.types.Panel):
    bl_idname = "NODE_PT_LocationNode"
    bl_space_type = 'NODE_EDITOR'
    bl_label = "Add Location Node"
    bl_region_type = "UI"
    bl_category = "Tool"
    def draw(self, context):
        material = context.material
        if hasattr(material, 'node_tree'):
            node_tree = material.node_tree
            layout = self.layout
            row = layout.row()
            row.prop_search(node_tree, "target_name", context.scene, "objects")
            row = layout.row()
            row.operator("nodetree.locationnode")

class NODE_OT_Locationbnode(bpy.types.Operator):
    bl_idname = "nodetree.locationnode"
    bl_label = "Add object location node"
    def execute(self, context):
        node_tree = context.material.node_tree
        target_name = node_tree.target_name
        # ノードの作成
        drive_node = node_tree.nodes.new( 'ShaderNodeCombineXYZ' )
        drive_node.name = "LocationNode"
        drive_node.label = target_name + ".location"
        target_obj = bpy.data.objects[target_name]
        for i in range(3):
            # ノードの値をドライバで設定
            prop = drive_node.inputs[i].driver_add('default_value')
            #スクリプトタイプのドライバ
            prop.driver.type =  'SCRIPTED'
            #ドライバ変数の作成
            var = prop.driver.variables.new()
            var.name = 'location'
            var.type = 'SINGLE_PROP'
            # ドライバのターゲットの設定
            var.targets[0].id = target_obj
            var.targets[0].data_path = 'location[%s]' % i
            #式の入力
            prop.driver.expression = 'location'
        return {'FINISHED'}

classes = (
    NodeLocationNoePanel,
    NODE_OT_Locationbnode,
    )
def register():
    bpy.types.NodeTree.target_name = bpy.props.StringProperty(name = "Objact")
    #classes
    for cls in classes:
        bpy.utils.register_class(cls)
def unregister():
    del bpy.types.NodeTree.target_name
    #classes
    for cls in classes:
        bpy.utils.unregister_class(cls)
if __name__ == "__main__":
    register()
```
アドオンを有効にするとシェーダーエディターのツールタブに
”Add Location Node”　という項目が追加します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/1d2a6e4c-dad0-78b2-8f6d-37b42fa71c9c.png)
Object:の項目で座標を取得したいオブジェクトを選択して
Add object location node　のボタンを押すと　目的のオブジェクトの座標を取得するノードが作成されます

例えば冒頭のようにマテリアルのついたオブジェクトと目的のオブジェクトの座標から方向ベクトルを取得して
法線との内積をとれば　ライティングのようなことができるようになります
![212031201.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/151493/f7d25405-e435-96cf-0814-cd95e36fbd17.gif)
このスクリプト単体では使いどころが少ないかもしれませんが

例えば既存のトゥーンシェーダーマテリアルだと　オブジェクトを一緒に頒布することになっているものが
これをうまく利用すれば　スクリプトだけで設定できるようになるかもしれません