「Dev:2.8/Source/Viewport/PyNodeGLSL」の版間の差分
細 (1版 をインポートしました) |
|
(相違点なし)
|
2018年6月29日 (金) 06:21時点における最新版
目次
Pynode GLSL
This is the first step towards accommodating GLSL code snippets definition in PyNodes. Which in turn is related to the proposal for the viewport plan of action.
The overall idea is to allow for external engines to define an optional GLSL code for each node. This would automatically be picked up by the Eevee engine. Also, this would allow for external engines to benefit from Blender’s internal GLSL code parser, for their own viewport drawings.
Cycles Engine
class CyclesRender(bpy.types.RenderEngine):
# Define whether or not to use OpenGL/Vulkan API
bl_use_realtime_engine = False
# This string will be added at to all shaders
# Put redundant GLSL code here
bl_gpu_library = """
#define CYCLES_M_PI 3.14
vec3 CYCLES_to_tangent(...) {...};
float CYCLES_saturate(...) {...};
...
"""
The bl_gpu_library contains all functions shared between nodes to avoid code duplication. All functions, variables and constants should have a prefix to avoid namespace conflicts later.
Cycles Nodes
class CyclesMixShaderNode(bpy.types.ShaderNode):
# with which render engine this node will be executed
bl_compatibility = {'CYCLES'}
# Code is defined here in case any realtime RenderEngines want to use it
# Multiple functions can define in there
bl_gpu_code = {'CYCLES' : "void node_shader_mix_shader(...) {out_col = ...}"}
# Logic to call GLSL functions for the node itself
def gpu_exec(self, ins, outs):
return gpu_stack_link('node_shader_mix_shader', ins, outs)
Note : only bpy.types.ShaderNode will inherit theses properties.
This means we need to port all cycles nodes to this API. The gpu_exec function should be a direct port from the gpu_shader_*** functions defined in source/blender/nodes/shader/nodes/node_shader_*. The bl_gpu_code will be the functions needed by this node that are in source/blender/gpu/shaders/gpu_shader_material.glsl The bl_gpu_code will be only added once per shader.
The compatibility flag is here to prune any node not compatible with the engine before parsing the tree. It is not only for realtime engines but also for offline engines. Any node not compatible with the current Engine will be clearly indicated to the user (gray out, ...).
Any node that does not have GLSL code will be considered incompatible to realtime engines.
Other Engine
Now we will take a look at how a new engine is implemented. For this exemple, we use the future Eevee Engine.
import bpy
class EeveeRender(RenderEngine):
# Enable OpenGL/Vulkan rendering
bl_use_realtime_engine = True
# Enable Internal Features
bl_gpu_features = {'PROBES', 'SHADOWS', 'LIGHTS'...}
# Define it's own library
bl_gpu_library = """
#define EEVEE_M_PI 3.14
vec3 EEVEE_to_tangent(...)
...
"""
# Convertion functions
bl_gpu_converts ="""
vec4 float_to_vec4(in float val) {return vec4(val);}
...
"""
def register():
# This line add 'EEVEE' to the bl_compatibility of CyclesMixShaderNode
# and reuse Cycles GLSL code
add_engine_compatibility('EEVEE', bpy.types.ShaderNodeMixShader)
# You can also specify you own glsl for the node
add_engine_compatibility('EEVEE', bpy.types.ShaderNodeMixShader, "Custom GLSL Code here")
# Reconstruct the GLSL hash after all compatibility changes
reconstruct_glsl_library()
def unregister():
remove_engine_compatibility('EEVEE', bpy.types.ShaderNodeType)
reconstruct_glsl_library()
The bl_gpu_converts is mandatory to convert i/o sockets in the tree. If a link use an undefined conversion, we let the shader not compile and a use default one.
After parsing, the shader code will look like something like this.
Example 1
Running Eevee, with 2 eevee nodes.
eevee.gpu_library node1.eevee.gpu_code node2.eevee.gpu_code eevee.gpu_converts void main(){ node1(a,b); node2(b,c); gl_FragColor = c; }
Only one library and 2 gpu_code are loaded.
Example 2 :
Running Eevee, with 1 eevee node and 1 compatible cycles node.
cycles.gpu_library node2.gpu_code.cycles eevee.gpu_library node1.gpu_code.eevee eevee.gpu_converts void main(){ node1(a,b); node2(b,c); gl_FragColor = c; }
This time the 2 libraries are needed because we are using code from the 2 engines.