Rendering pipeline nodes
This commit is contained in:
parent
db8088862a
commit
6a7d93ce04
|
@ -56,7 +56,7 @@
|
|||
},
|
||||
{
|
||||
"command": "draw_quad",
|
||||
"params": ["material_resource", "material1", "env_map"]
|
||||
"params": ["material_resource/material1/env_map"]
|
||||
},
|
||||
{
|
||||
"command": "bind_target",
|
||||
|
@ -64,7 +64,7 @@
|
|||
},
|
||||
{
|
||||
"command": "draw_quad",
|
||||
"params": ["material_resource", "material_deferred", "deferred_pass"]
|
||||
"params": ["material_resource/material_deferred/deferred_pass"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -2058,7 +2058,7 @@ class ArmoryExporter(bpy.types.Operator, ExportHelper):
|
|||
o.draw_calls_sort = 'front_to_back'
|
||||
else:
|
||||
o.draw_calls_sort = 'none'
|
||||
o.pipeline = object.pipeline_path
|
||||
o.pipeline = object.pipeline_path + '/' + object.pipeline_path # Same file name and id
|
||||
|
||||
if 'Background' in bpy.data.worlds[0].node_tree.nodes: # TODO: parse node tree
|
||||
col = bpy.data.worlds[0].node_tree.nodes['Background'].inputs[0].default_value
|
||||
|
|
100
blender/nodes.py
100
blender/nodes.py
|
@ -1,6 +1,8 @@
|
|||
import bpy
|
||||
from bpy.types import NodeTree, Node, NodeSocket
|
||||
from bpy.props import *
|
||||
import os
|
||||
import sys
|
||||
# Implementation of custom nodes from Python
|
||||
|
||||
# Derived from the NodeTree base type, similar to Menu, Operator, Panel, etc.
|
||||
|
@ -13,8 +15,8 @@ class CGTree(NodeTree):
|
|||
bl_label = 'CG Node Tree'
|
||||
# Icon identifier
|
||||
# NOTE: If no icon is defined, the node tree will not show up in the editor header!
|
||||
# This can be used to make additional tree types for groups and similar nodes (see below)
|
||||
# Only one base tree class is needed in the editor for selecting the general category
|
||||
# This can be used to make additional tree types for groups and similar nodes (see below)
|
||||
# Only one base tree class is needed in the editor for selecting the general category
|
||||
bl_icon = 'GAME'
|
||||
|
||||
#def update(self):
|
||||
|
@ -47,7 +49,7 @@ class TransformNode(Node, CGTreeNode):
|
|||
# Initialization function, called when a new node is created.
|
||||
# This is the most common place to create the sockets for a node, as shown below.
|
||||
# NOTE: this is not the same as the standard __init__ function in Python, which is
|
||||
# a purely internal Python method and unknown to the node system!
|
||||
# a purely internal Python method and unknown to the node system!
|
||||
def init(self, context):
|
||||
self.inputs.new('NodeSocketVector', "Position")
|
||||
self.inputs.new('NodeSocketVector', "Rotation")
|
||||
|
@ -215,3 +217,95 @@ def register():
|
|||
def unregister():
|
||||
nodeitems_utils.unregister_node_categories("CG_NODES")
|
||||
bpy.utils.unregister_module(__name__)
|
||||
|
||||
# Generating node sources
|
||||
def buildNodeTrees():
|
||||
s = bpy.data.filepath.split(os.path.sep)
|
||||
s.pop()
|
||||
fp = os.path.sep.join(s)
|
||||
os.chdir(fp)
|
||||
|
||||
# Make sure package dir exists
|
||||
if not os.path.exists('Sources/' + bpy.data.worlds[0].CGProjectPackage.replace(".", "/")):
|
||||
os.makedirs('Sources/' + bpy.data.worlds[0].CGProjectPackage.replace(".", "/"))
|
||||
|
||||
# Export node scripts
|
||||
for node_group in bpy.data.node_groups:
|
||||
if node_group.bl_idname == 'CGTreeType': # Build only cycles game trees
|
||||
buildNodeTree(node_group)
|
||||
|
||||
def buildNodeTree(node_group):
|
||||
rn = getRootNode(node_group)
|
||||
|
||||
path = 'Sources/' + bpy.data.worlds[0].CGProjectPackage.replace(".", "/") + "/"
|
||||
|
||||
node_group_name = node_group.name.replace('.', '_')
|
||||
|
||||
with open(path + node_group_name + '.hx', 'w') as f:
|
||||
f.write('package ' + bpy.data.worlds[0].CGProjectPackage + ';\n\n')
|
||||
f.write('import cycles.node.*;\n\n')
|
||||
f.write('class ' + node_group_name + ' extends cycles.trait.NodeExecutor {\n\n')
|
||||
f.write('\tpublic function new() { super(); requestAdd(add); }\n\n')
|
||||
f.write('\tfunction add() {\n')
|
||||
# Make sure root node exists
|
||||
if rn != None:
|
||||
name = '_' + rn.name.replace(".", "_").replace("@", "")
|
||||
buildNode(node_group, rn, f, [])
|
||||
f.write('\n\t\tstart(' + name + ');\n')
|
||||
f.write('\t}\n')
|
||||
f.write('}\n')
|
||||
|
||||
def buildNode(node_group, node, f, created_nodes):
|
||||
# Get node name
|
||||
name = '_' + node.name.replace(".", "_").replace("@", "")
|
||||
|
||||
# Check if node already exists
|
||||
for n in created_nodes:
|
||||
if n == name:
|
||||
return name
|
||||
|
||||
# Create node
|
||||
type = node.name.split(".")[0].replace("@", "") + "Node"
|
||||
f.write('\t\tvar ' + name + ' = new ' + type + '();\n')
|
||||
created_nodes.append(name)
|
||||
|
||||
# Variables
|
||||
if type == "TransformNode":
|
||||
f.write('\t\t' + name + '.transform = node.transform;\n')
|
||||
|
||||
# Create inputs
|
||||
for inp in node.inputs:
|
||||
# Is linked - find node
|
||||
inpname = ''
|
||||
if inp.is_linked:
|
||||
n = findNodeByLink(node_group, node, inp)
|
||||
inpname = buildNode(node_group, n, f, created_nodes)
|
||||
# Not linked - create node with default values
|
||||
else:
|
||||
inpname = buildDefaultNode(inp)
|
||||
|
||||
# Add input
|
||||
f.write('\t\t' + name + '.inputs.push(' + inpname + ');\n')
|
||||
|
||||
return name
|
||||
|
||||
def findNodeByLink(node_group, to_node, inp):
|
||||
for link in node_group.links:
|
||||
if link.to_node == to_node and link.to_socket == inp:
|
||||
return link.from_node
|
||||
|
||||
def getRootNode(node_group):
|
||||
for n in node_group.nodes:
|
||||
if n.outputs[0].is_linked == False:
|
||||
return n
|
||||
|
||||
def buildDefaultNode(inp):
|
||||
inpname = ''
|
||||
if inp.type == "VECTOR":
|
||||
inpname = 'VectorNode.create(' + str(inp.default_value[0]) + ', ' + str(inp.default_value[1]) + ", " + str(inp.default_value[2]) + ')'
|
||||
elif inp.type == "VALUE":
|
||||
inpname = 'FloatNode.create(' + str(inp.default_value) + ')'
|
||||
elif inp.type == 'BOOLEAN':
|
||||
inpname = 'BoolNode.create(' + str(inp.default_value).lower() + ')'
|
||||
|
||||
return inpname
|
||||
|
|
295
blender/pipeline_nodes.py
Executable file
295
blender/pipeline_nodes.py
Executable file
|
@ -0,0 +1,295 @@
|
|||
import bpy
|
||||
from bpy.types import NodeTree, Node, NodeSocket
|
||||
from bpy.props import *
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
|
||||
class CGPipelineTree(NodeTree):
|
||||
'''Pipeline nodes'''
|
||||
bl_idname = 'CGPipelineTreeType'
|
||||
bl_label = 'CG Pipeline Node Tree'
|
||||
bl_icon = 'GAME'
|
||||
|
||||
class CGPipelineTreeNode:
|
||||
@classmethod
|
||||
def poll(cls, ntree):
|
||||
return ntree.bl_idname == 'CGPipelineTreeType'
|
||||
|
||||
class DrawGeometryNode(Node, CGPipelineTreeNode):
|
||||
'''A custom node'''
|
||||
bl_idname = 'DrawGeometryNodeType'
|
||||
bl_label = 'Draw Geometry'
|
||||
bl_icon = 'SOUND'
|
||||
|
||||
def init(self, context):
|
||||
self.inputs.new('NodeSocketShader', "Stage")
|
||||
self.inputs.new('NodeSocketString', "Context")
|
||||
|
||||
self.outputs.new('NodeSocketShader', "Stage")
|
||||
|
||||
def copy(self, node):
|
||||
print("Copying from node ", node)
|
||||
|
||||
def free(self):
|
||||
print("Removing node ", self, ", Goodbye!")
|
||||
|
||||
class ClearTargetNode(Node, CGPipelineTreeNode):
|
||||
'''A custom node'''
|
||||
bl_idname = 'ClearTargetNodeType'
|
||||
bl_label = 'Clear Target'
|
||||
bl_icon = 'SOUND'
|
||||
|
||||
def init(self, context):
|
||||
self.inputs.new('NodeSocketShader', "Stage")
|
||||
self.inputs.new('NodeSocketBool', "Color")
|
||||
self.inputs.new('NodeSocketBool', "Depth")
|
||||
|
||||
self.outputs.new('NodeSocketShader', "Stage")
|
||||
|
||||
def copy(self, node):
|
||||
print("Copying from node ", node)
|
||||
|
||||
def free(self):
|
||||
print("Removing node ", self, ", Goodbye!")
|
||||
|
||||
class SetTargetNode(Node, CGPipelineTreeNode):
|
||||
'''A custom node'''
|
||||
bl_idname = 'SetTargetNodeType'
|
||||
bl_label = 'Set Target'
|
||||
bl_icon = 'SOUND'
|
||||
|
||||
def init(self, context):
|
||||
self.inputs.new('NodeSocketShader', "Stage")
|
||||
self.inputs.new('NodeSocketShader', "Target")
|
||||
|
||||
self.outputs.new('NodeSocketShader', "Stage")
|
||||
|
||||
def copy(self, node):
|
||||
print("Copying from node ", node)
|
||||
|
||||
def free(self):
|
||||
print("Removing node ", self, ", Goodbye!")
|
||||
|
||||
class TargetNode(Node, CGPipelineTreeNode):
|
||||
'''A custom node'''
|
||||
bl_idname = 'TargetNodeType'
|
||||
bl_label = 'Target'
|
||||
bl_icon = 'SOUND'
|
||||
|
||||
def init(self, context):
|
||||
self.inputs.new('NodeSocketString', "ID")
|
||||
self.inputs.new('NodeSocketInt', "Width")
|
||||
self.inputs.new('NodeSocketInt', "Height")
|
||||
self.inputs.new('NodeSocketInt', "Color Buffers")
|
||||
self.inputs.new('NodeSocketBool', "Depth")
|
||||
self.inputs.new('NodeSocketString', "Format")
|
||||
|
||||
self.outputs.new('NodeSocketShader', "Target")
|
||||
|
||||
def copy(self, node):
|
||||
print("Copying from node ", node)
|
||||
|
||||
def free(self):
|
||||
print("Removing node ", self, ", Goodbye!")
|
||||
|
||||
class FramebufferNode(Node, CGPipelineTreeNode):
|
||||
'''A custom node'''
|
||||
bl_idname = 'FramebufferNodeType'
|
||||
bl_label = 'Framebuffer'
|
||||
bl_icon = 'SOUND'
|
||||
|
||||
def init(self, context):
|
||||
self.outputs.new('NodeSocketShader', "Target")
|
||||
|
||||
def copy(self, node):
|
||||
print("Copying from node ", node)
|
||||
|
||||
def free(self):
|
||||
print("Removing node ", self, ", Goodbye!")
|
||||
|
||||
class BindTargetNode(Node, CGPipelineTreeNode):
|
||||
'''A custom node'''
|
||||
bl_idname = 'BindTargetNodeType'
|
||||
bl_label = 'Bind Target'
|
||||
bl_icon = 'SOUND'
|
||||
|
||||
def init(self, context):
|
||||
self.inputs.new('NodeSocketShader', "Stage")
|
||||
self.inputs.new('NodeSocketShader', "Target")
|
||||
self.inputs.new('NodeSocketString', "Constant")
|
||||
|
||||
self.outputs.new('NodeSocketShader', "Stage")
|
||||
|
||||
def copy(self, node):
|
||||
print("Copying from node ", node)
|
||||
|
||||
def free(self):
|
||||
print("Removing node ", self, ", Goodbye!")
|
||||
|
||||
class DrawQuadNode(Node, CGPipelineTreeNode):
|
||||
'''A custom node'''
|
||||
bl_idname = 'DrawQuadNodeType'
|
||||
bl_label = 'Draw Quad'
|
||||
bl_icon = 'SOUND'
|
||||
|
||||
def init(self, context):
|
||||
self.inputs.new('NodeSocketShader', "Stage")
|
||||
self.inputs.new('NodeSocketString', "Material Context")
|
||||
|
||||
self.outputs.new('NodeSocketShader', "Stage")
|
||||
|
||||
def copy(self, node):
|
||||
print("Copying from node ", node)
|
||||
|
||||
def free(self):
|
||||
print("Removing node ", self, ", Goodbye!")
|
||||
|
||||
### Node Categories ###
|
||||
# Node categories are a python system for automatically
|
||||
# extending the Add menu, toolbar panels and search operator.
|
||||
# For more examples see release/scripts/startup/nodeitems_builtins.py
|
||||
|
||||
import nodeitems_utils
|
||||
from nodeitems_utils import NodeCategory, NodeItem
|
||||
|
||||
class MyPipelineNodeCategory(NodeCategory):
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.space_data.tree_type == 'CGPipelineTreeType'
|
||||
|
||||
node_categories = [
|
||||
MyPipelineNodeCategory("PIPELINENODES", "Pipeline Nodes", items=[
|
||||
NodeItem("DrawGeometryNodeType"),
|
||||
NodeItem("ClearTargetNodeType"),
|
||||
NodeItem("SetTargetNodeType"),
|
||||
NodeItem("BindTargetNodeType"),
|
||||
NodeItem("DrawQuadNodeType"),
|
||||
NodeItem("TargetNodeType"),
|
||||
NodeItem("FramebufferNodeType"),
|
||||
]),
|
||||
]
|
||||
|
||||
def register():
|
||||
bpy.utils.register_module(__name__)
|
||||
try:
|
||||
nodeitems_utils.register_node_categories("CG_PIELINE_PNODES", node_categories)
|
||||
except:
|
||||
pass
|
||||
|
||||
def unregister():
|
||||
nodeitems_utils.unregister_node_categories("CG_PIELINE_PNODES")
|
||||
bpy.utils.unregister_module(__name__)
|
||||
|
||||
|
||||
# Generating pipeline resources
|
||||
class Object:
|
||||
def to_JSON(self):
|
||||
# return json.dumps(self, default=lambda o: o.__dict__, separators=(',',':'))
|
||||
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
|
||||
|
||||
def buildNodeTrees():
|
||||
s = bpy.data.filepath.split(os.path.sep)
|
||||
s.pop()
|
||||
fp = os.path.sep.join(s)
|
||||
os.chdir(fp)
|
||||
|
||||
# Make sure Assets dir exists
|
||||
if not os.path.exists('Assets/generated/pipelines'):
|
||||
os.makedirs('Assets/generated/pipelines')
|
||||
|
||||
# Export pipelines
|
||||
for node_group in bpy.data.node_groups:
|
||||
if node_group.bl_idname == 'CGPipelineTreeType': # Build only render pipeline trees
|
||||
buildNodeTree(node_group)
|
||||
|
||||
def buildNodeTree(node_group):
|
||||
output = Object()
|
||||
res = Object()
|
||||
output.pipeline_resources = [res]
|
||||
|
||||
path = 'Assets/generated/pipelines/'
|
||||
node_group_name = node_group.name.replace('.', '_')
|
||||
|
||||
res.id = node_group_name
|
||||
res.render_targets = get_render_targets(node_group)
|
||||
res.stages = []
|
||||
|
||||
rn = getRootNode(node_group)
|
||||
buildNode(res, rn, node_group)
|
||||
|
||||
with open(path + node_group_name + '.json', 'w') as f:
|
||||
f.write(output.to_JSON())
|
||||
|
||||
def buildNode(res, node, node_group):
|
||||
stage = Object()
|
||||
stage.params = []
|
||||
|
||||
if node.bl_idname == 'SetTargetNodeType':
|
||||
stage.command = 'set_target'
|
||||
targetNode = findNodeByLink(node_group, node, node.inputs[1])
|
||||
if targetNode.bl_idname == 'TargetNodeType':
|
||||
targetId = targetNode.inputs[0].default_value
|
||||
else: # Framebuffer
|
||||
targetId = ''
|
||||
stage.params.append(targetId)
|
||||
|
||||
elif node.bl_idname == 'ClearTargetNodeType':
|
||||
stage.command = 'clear_target'
|
||||
if node.inputs[1].default_value == True:
|
||||
stage.params.append('color')
|
||||
if node.inputs[2].default_value == True:
|
||||
stage.params.append('depth')
|
||||
|
||||
elif node.bl_idname == 'DrawGeometryNodeType':
|
||||
stage.command = 'draw_geometry'
|
||||
stage.params.append(node.inputs[1].default_value) # Context
|
||||
|
||||
elif node.bl_idname == 'BindTargetNodeType':
|
||||
stage.command = 'bind_target'
|
||||
targetNode = findNodeByLink(node_group, node, node.inputs[1])
|
||||
if targetNode.bl_idname == 'TargetNodeType':
|
||||
targetId = targetNode.inputs[0].default_value
|
||||
stage.params.append(targetId)
|
||||
|
||||
elif node.bl_idname == 'DrawQuadNodeType':
|
||||
stage.command = 'draw_quad'
|
||||
stage.params.append(node.inputs[1].default_value) # Material context
|
||||
|
||||
res.stages.append(stage)
|
||||
|
||||
# Build next stage
|
||||
if node.outputs[0].is_linked:
|
||||
stageNode = findNodeByFromLink(node_group, node, node.outputs[0])
|
||||
buildNode(res, stageNode, node_group)
|
||||
|
||||
def findNodeByLink(node_group, to_node, inp):
|
||||
for link in node_group.links:
|
||||
if link.to_node == to_node and link.to_socket == inp:
|
||||
return link.from_node
|
||||
|
||||
def findNodeByFromLink(node_group, from_node, outp):
|
||||
for link in node_group.links:
|
||||
if link.from_node == from_node and link.from_socket == outp:
|
||||
return link.to_node
|
||||
|
||||
def getRootNode(node_group):
|
||||
# First node with empty stage input
|
||||
for n in node_group.nodes:
|
||||
if len(n.inputs) > 0 and n.inputs[0].is_linked == False and n.inputs[0].name == 'Stage':
|
||||
return n
|
||||
|
||||
def get_render_targets(node_group):
|
||||
render_targets = []
|
||||
for n in node_group.nodes:
|
||||
if n.bl_idname == 'TargetNodeType':
|
||||
target = Object()
|
||||
target.id = n.inputs[0].default_value
|
||||
target.width = n.inputs[1].default_value
|
||||
target.height = n.inputs[2].default_value
|
||||
target.color_buffers = n.inputs[3].default_value
|
||||
target.depth = n.inputs[4].default_value
|
||||
target.format = n.inputs[5].default_value
|
||||
render_targets.append(target)
|
||||
return render_targets
|
||||
|
|
@ -9,6 +9,8 @@ import subprocess
|
|||
import atexit
|
||||
import webbrowser
|
||||
import write_data
|
||||
import nodes
|
||||
import pipeline_nodes
|
||||
from armory import ArmoryExporter
|
||||
|
||||
def defaultSettings():
|
||||
|
@ -159,7 +161,8 @@ def buildProject(self, build_type=0):
|
|||
#area.type = old_type
|
||||
|
||||
# Auto-build nodes # TODO: only if needed
|
||||
buildNodeTrees()
|
||||
nodes.buildNodeTrees()
|
||||
pipeline_nodes.buildNodeTrees()
|
||||
|
||||
# Set dir
|
||||
s = bpy.data.filepath.split(os.path.sep)
|
||||
|
@ -272,99 +275,6 @@ class OBJECT_OT_CLEANButton(bpy.types.Operator):
|
|||
cleanProject(self)
|
||||
return{'FINISHED'}
|
||||
|
||||
|
||||
|
||||
def buildNodeTrees():
|
||||
s = bpy.data.filepath.split(os.path.sep)
|
||||
s.pop()
|
||||
fp = os.path.sep.join(s)
|
||||
os.chdir(fp)
|
||||
|
||||
# Make sure package dir exists
|
||||
if not os.path.exists('Sources/' + bpy.data.worlds[0].CGProjectPackage.replace(".", "/")):
|
||||
os.makedirs('Sources/' + bpy.data.worlds[0].CGProjectPackage.replace(".", "/"))
|
||||
|
||||
# Export node scripts
|
||||
for node_group in bpy.data.node_groups:
|
||||
if node_group.bl_idname == 'CGTreeType': # Build only cycles game trees
|
||||
buildNodeTree(node_group)
|
||||
|
||||
def buildNodeTree(node_group):
|
||||
rn = getRootNode(node_group)
|
||||
|
||||
path = 'Sources/' + bpy.data.worlds[0].CGProjectPackage.replace(".", "/") + "/"
|
||||
|
||||
node_group_name = node_group.name.replace('.', '_')
|
||||
|
||||
with open(path + node_group_name + '.hx', 'w') as f:
|
||||
f.write('package ' + bpy.data.worlds[0].CGProjectPackage + ';\n\n')
|
||||
f.write('import cycles.node.*;\n\n')
|
||||
f.write('class ' + node_group_name + ' extends cycles.trait.NodeExecutor {\n\n')
|
||||
f.write('\tpublic function new() { super(); requestAdd(add); }\n\n')
|
||||
f.write('\tfunction add() {\n')
|
||||
# Make sure root node exists
|
||||
if rn != None:
|
||||
name = '_' + rn.name.replace(".", "_").replace("@", "")
|
||||
buildNode(node_group, rn, f, [])
|
||||
f.write('\n\t\tstart(' + name + ');\n')
|
||||
f.write('\t}\n')
|
||||
f.write('}\n')
|
||||
|
||||
def buildNode(node_group, node, f, created_nodes):
|
||||
# Get node name
|
||||
name = '_' + node.name.replace(".", "_").replace("@", "")
|
||||
|
||||
# Check if node already exists
|
||||
for n in created_nodes:
|
||||
if n == name:
|
||||
return name
|
||||
|
||||
# Create node
|
||||
type = node.name.split(".")[0].replace("@", "") + "Node"
|
||||
f.write('\t\tvar ' + name + ' = new ' + type + '();\n')
|
||||
created_nodes.append(name)
|
||||
|
||||
# Variables
|
||||
if type == "TransformNode":
|
||||
f.write('\t\t' + name + '.transform = node.transform;\n')
|
||||
|
||||
# Create inputs
|
||||
for inp in node.inputs:
|
||||
# Is linked - find node
|
||||
inpname = ''
|
||||
if inp.is_linked:
|
||||
n = findNodeByLink(node_group, node, inp)
|
||||
inpname = buildNode(node_group, n, f, created_nodes)
|
||||
# Not linked - create node with default values
|
||||
else:
|
||||
inpname = buildDefaultNode(inp)
|
||||
|
||||
# Add input
|
||||
f.write('\t\t' + name + '.inputs.push(' + inpname + ');\n')
|
||||
|
||||
return name
|
||||
|
||||
def findNodeByLink(node_group, to_node, inp):
|
||||
for link in node_group.links:
|
||||
if link.to_node == to_node and link.to_socket == inp:
|
||||
return link.from_node
|
||||
|
||||
def getRootNode(node_group):
|
||||
for n in node_group.nodes:
|
||||
if n.outputs[0].is_linked == False:
|
||||
return n
|
||||
|
||||
def buildDefaultNode(inp):
|
||||
inpname = ''
|
||||
if inp.type == "VECTOR":
|
||||
inpname = 'VectorNode.create(' + str(inp.default_value[0]) + ', ' + str(inp.default_value[1]) + ", " + str(inp.default_value[2]) + ')'
|
||||
elif inp.type == "VALUE":
|
||||
inpname = 'FloatNode.create(' + str(inp.default_value) + ')'
|
||||
elif inp.type == 'BOOLEAN':
|
||||
inpname = 'BoolNode.create(' + str(inp.default_value).lower() + ')'
|
||||
|
||||
return inpname
|
||||
|
||||
# Registration
|
||||
def register():
|
||||
bpy.utils.register_module(__name__)
|
||||
|
|
|
@ -61,7 +61,7 @@ class DataPropsPanel(bpy.types.Panel):
|
|||
if obj.type == 'CAMERA':
|
||||
layout.prop(obj.data, 'frustum_culling')
|
||||
layout.prop(obj.data, 'sort_front_to_back')
|
||||
layout.prop(obj.data, 'pipeline_path')
|
||||
layout.prop_search(obj.data, "pipeline_path", bpy.data, "node_groups")
|
||||
layout.prop(obj.data, 'pipeline_pass')
|
||||
elif obj.type == 'MESH':
|
||||
layout.prop(obj.data, 'static_usage')
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import project
|
||||
import nodes
|
||||
import pipeline_nodes
|
||||
import armory
|
||||
import traits_animation
|
||||
import traits
|
||||
|
@ -8,6 +9,7 @@ import props
|
|||
def register():
|
||||
project.register()
|
||||
nodes.register()
|
||||
pipeline_nodes.register()
|
||||
armory.register()
|
||||
traits_animation.register()
|
||||
traits.register()
|
||||
|
@ -16,6 +18,7 @@ def register():
|
|||
def unregister():
|
||||
project.unregister()
|
||||
nodes.unregister()
|
||||
pipeline_nodes.unregister()
|
||||
armory.unregister()
|
||||
traits_animation.unregister()
|
||||
traits.unregister()
|
||||
|
|
Loading…
Reference in a new issue