Shader Pynodes for Blender 2.8

提供: wiki
移動先: 案内検索

Main Specification

Here is rough roadmap for shader pynodes developing.

  1. ✔ Make simple custom Render engine with one input and output (e.g. Geometry from Cycles and Output) nodes.
  2. ✔ Make it possible to implement the following node method with python: NodeGPUExecFunction gpufunc.
  3. ✔ Port gpu_stack_link etc
  4. ✔ Implement Geometry and Output nodes using functions ported in previous point
  5. Implement Texture node (API for texture passing), - waiting for D113
  6. ✔ Implement procedural texture node
  7. Handle bl_compatibility
    1. ✔ automatic generation of "ADD" menu
    2. "add compatibility" API for existing nodes
      1. ✔ New node for old engine: add support for non-native engine libs
      2. ✔ Old node for new engine
      3. Gray out non-compatible nodes
    3. ✔ use common set for node items in add menu, handled by compatible() method of node class
  8. Implement all stuff for shader common code, defined in Render Engine class:
    1. ✔ Parse bl_gpu_library
    2. bl_use_realtime_engine
    3. bl_gpu_features
    4. bl_gpu_converts
    5. reconstruct_glsl_library
  9. Port Cycles nodes to python
  10. ✔ Handle Muting (update_internal_links): allow default behavior for all shader nodes, disable muting for "Output" category
  11. Handle blend file compatibility

Current State

Geometry, Output, Passthrough nodes are implemented using python.

Py shaders begining.gif

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")