Shader Pynodes for Blender 2.8
Here is rough roadmap for shader pynodes developing.
- ✔ Make simple custom Render engine with one input and output (e.g. Geometry from Cycles and Output) nodes.
- ✔ Make it possible to implement the following node method with python: NodeGPUExecFunction gpufunc.
- ✔ Port gpu_stack_link etc
- ✔ Implement Geometry and Output nodes using functions ported in previous point
- Implement Texture node (API for texture passing), - waiting for D113
- ✔ Implement procedural texture node
- Handle bl_compatibility
- ✔ automatic generation of "ADD" menu
- "add compatibility" API for existing nodes
- ✔ New node for old engine: add support for non-native engine libs
- ✔ Old node for new engine
- Gray out non-compatible nodes
- ✔ use common set for node items in add menu, handled by compatible() method of node class
- Implement all stuff for shader common code, defined in Render Engine class:
- ✔ Parse bl_gpu_library
- bl_use_realtime_engine
- bl_gpu_features
- bl_gpu_converts
- reconstruct_glsl_library
- Port Cycles nodes to python
- ✔ Handle Muting (update_internal_links): allow default behavior for all shader nodes, disable muting for "Output" category
- Handle blend file compatibility
Current State
Geometry, Output, Passthrough nodes are implemented using python.
Python example (not complete, but sufficient for API review)
class PyGLSLRender(bpy.types.RenderEngine):
bl_idname = 'PyGLSL'
bl_label = "PyGLSL Render"
bl_use_shading_nodes = True
bl_use_preview = False
bl_use_shading_nodes_custom = False
class PyGLSLNode:
@classmethod
def poll(cls, ntree):
return ntree.bl_idname == 'PyGLSL'
class PyGLSL_node_geom(bpy.types.ShaderNode, PyGLSLNode):
bl_idname = 'PyGLSL_node_geom'
bl_label = 'PyGLSL Geometry'
bl_compatibility={'CYCLES', 'PyGLSL'}
bl_category = "Input"
bl_class = "INPUT"
def gpufunc(self, ins, outs):
v_pos = GPULink(builtins.GPU_VIEW_POSITION)
v_nor = GPULink(builtins.GPU_VIEW_NORMAL)
i_vmat = GPULink(builtins.GPU_INVERSE_VIEW_MATRIX)
return GPU_link_stack(self, "node_geometry", ins, outs, v_pos, v_nor, i_vmat)
def init(self, context):
self.outputs.new("NodeSocketVector", "Position")
self.outputs.new("NodeSocketVector", "Normal")
self.outputs.new("NodeSocketVector", "Tangent")
self.outputs.new("NodeSocketVector", "True Normal")
self.outputs.new("NodeSocketVector", "Incoming")
self.outputs.new("NodeSocketVector", "Parametric")
self.outputs.new("NodeSocketFloat", "Backfacing")
self.outputs.new("NodeSocketFloat", "Pointiness")
passthrough_lib ='''
void pass_through(vec3 col, out vec3 outcol)
{
outcol = col;
}
'''
class PyGLSL_node_passthrough(bpy.types.ShaderNode, PyGLSLNode):
bl_idname = 'PyGLSL_node_passthrough'
bl_label = 'PyGLSL Passthrough'
bl_compatibility = {'CYCLES', 'PyGLSL'}
bl_category = "Converter"
bl_gpu_code = {"CYCLES": passthrough_lib, 'PyGLSL': passthrough_lib}
def gpufunc(self, ins, outs):
i = GPULink(ins.array[0])
o = GPULink(outs.array[0])
ret = GPU_link("pass_through", [i, o])
return ret
def init(self, context):
s = self.inputs.new("NodeSocketVector", "In")
s.hide_value = True
self.outputs.new("NodeSocketVector", "Out")
class PyGLSL_node_output(bpy.types.ShaderNode, PyGLSLNode):
bl_idname = 'PyGLSL_node_output'
bl_label = 'PyGLSL Output'
bl_compatibility = {'CYCLES', 'PyGLSL'}
bl_category = "Output"
bl_class = "OUTPUT"
def gpufunc(self, ins, outs):
out = GPULink()
GPU_link_stack(self, "node_output_material", ins, outs, out);
return GPU_link_output(out)
def init(self, context):
self.inputs.new("NodeSocketShader", "Surface")
self.inputs.new("NodeSocketShader", "Volume")
s = self.inputs.new("NodeSocketFloat", "Displacement")
s.hide_value = True
def unregister():
bpy.utils.unregister_module(__name__)
def register():
lib = '''
void node_geometry1(
vec3 I, vec3 N, mat4 toworld,
out vec3 position, out vec3 normal, out vec3 tangent,
out vec3 true_normal, out vec3 incoming, out vec3 parametric,
out float backfacing, out float pointiness)
{
position = (toworld * vec4(N, 0.0)).xyz;
}
'''
def gpufunc(self, ins, outs):
v_pos = GPULink(builtins.GPU_VIEW_POSITION)
v_nor = GPULink(builtins.GPU_VIEW_NORMAL)
i_vmat = GPULink(builtins.GPU_INVERSE_VIEW_MATRIX)
return GPU_link_stack(self, "node_geometry1", ins, outs, v_pos, v_nor, i_vmat)
bpy.utils.register_module(__name__)
add_engine_compatibility("PyGLSL", "ShaderNodeNewGeometry", (gpufunc, lib))
add_engine_compatibility("PyGLSL", "ShaderNodeOutputMaterial")