Merge pull request #1951 from MoritzBrueckner/cycles-nodes

More cycles nodes + improvements
This commit is contained in:
Lubos Lenco 2020-10-26 09:13:54 +01:00 committed by GitHub
commit 800498a78e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 78 additions and 43 deletions

View file

@ -1,5 +1,6 @@
import bpy
import arm.log as log
import arm.material.cycles as c
import arm.material.cycles_functions as c_functions
from arm.material.parser_state import ParserState
@ -42,49 +43,60 @@ def parse_invert(node: bpy.types.ShaderNodeInvert, out_socket: bpy.types.NodeSoc
def parse_mixrgb(node: bpy.types.ShaderNodeMixRGB, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str:
fac = c.parse_value_input(node.inputs[0])
fac_var = c.node_name(node.name) + '_fac'
state.curshader.write('float {0} = {1};'.format(fac_var, fac))
col1 = c.parse_vector_input(node.inputs[1])
col2 = c.parse_vector_input(node.inputs[2])
# Store factor in variable for linked factor input
if node.inputs[0].is_linked:
fac = c.node_name(node.name) + '_fac'
state.curshader.write('float {0} = {1};'.format(fac, c.parse_value_input(node.inputs[0])))
else:
fac = c.parse_value_input(node.inputs[0])
# TODO: Do not mix if factor is constant 0.0 or 1.0?
blend = node.blend_type
if blend == 'MIX':
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var)
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac)
elif blend == 'ADD':
out_col = 'mix({0}, {0} + {1}, {2})'.format(col1, col2, fac_var)
out_col = 'mix({0}, {0} + {1}, {2})'.format(col1, col2, fac)
elif blend == 'MULTIPLY':
out_col = 'mix({0}, {0} * {1}, {2})'.format(col1, col2, fac_var)
out_col = 'mix({0}, {0} * {1}, {2})'.format(col1, col2, fac)
elif blend == 'SUBTRACT':
out_col = 'mix({0}, {0} - {1}, {2})'.format(col1, col2, fac_var)
out_col = 'mix({0}, {0} - {1}, {2})'.format(col1, col2, fac)
elif blend == 'SCREEN':
out_col = '(vec3(1.0) - (vec3(1.0 - {2}) + {2} * (vec3(1.0) - {1})) * (vec3(1.0) - {0}))'.format(col1, col2, fac_var)
out_col = '(vec3(1.0) - (vec3(1.0 - {2}) + {2} * (vec3(1.0) - {1})) * (vec3(1.0) - {0}))'.format(col1, col2, fac)
elif blend == 'DIVIDE':
out_col = '(vec3((1.0 - {2}) * {0} + {2} * {0} / {1}))'.format(col1, col2, fac_var)
out_col = '(vec3((1.0 - {2}) * {0} + {2} * {0} / {1}))'.format(col1, col2, fac)
elif blend == 'DIFFERENCE':
out_col = 'mix({0}, abs({0} - {1}), {2})'.format(col1, col2, fac_var)
out_col = 'mix({0}, abs({0} - {1}), {2})'.format(col1, col2, fac)
elif blend == 'DARKEN':
out_col = 'min({0}, {1} * {2})'.format(col1, col2, fac_var)
out_col = 'min({0}, {1} * {2})'.format(col1, col2, fac)
elif blend == 'LIGHTEN':
out_col = 'max({0}, {1} * {2})'.format(col1, col2, fac_var)
out_col = 'max({0}, {1} * {2})'.format(col1, col2, fac)
elif blend == 'OVERLAY':
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac) # Revert to mix
elif blend == 'DODGE':
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac) # Revert to mix
elif blend == 'BURN':
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac) # Revert to mix
elif blend == 'HUE':
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac) # Revert to mix
elif blend == 'SATURATION':
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac) # Revert to mix
elif blend == 'VALUE':
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac) # Revert to mix
elif blend == 'COLOR':
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac) # Revert to mix
elif blend == 'SOFT_LIGHT':
out_col = '((1.0 - {2}) * {0} + {2} * ((vec3(1.0) - {0}) * {1} * {0} + {0} * (vec3(1.0) - (vec3(1.0) - {1}) * (vec3(1.0) - {0}))));'.format(col1, col2, fac)
elif blend == 'LINEAR_LIGHT':
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac) # Revert to mix
# out_col = '({0} + {2} * (2.0 * ({1} - vec3(0.5))))'.format(col1, col2, fac_var)
else:
log.warn(f'MixRGB node: unsupported blend type {node.blend_type}.')
return col1
if node.use_clamp:
return 'clamp({0}, vec3(0.0), vec3(1.0))'.format(out_col)
return out_col
@ -102,6 +114,5 @@ def parse_curvergb(node: bpy.types.ShaderNodeRGBCurve, out_socket: bpy.types.Nod
def parse_lightfalloff(node: bpy.types.ShaderNodeLightFalloff, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr:
# Constant, linear, quadratic
# Shaders default to quadratic for now
return '1.0'
# https://github.com/blender/blender/blob/master/source/blender/gpu/shaders/material/gpu_shader_material_light_falloff.glsl
return c.parse_value_input(node.inputs['Strength'])

View file

@ -316,9 +316,18 @@ def parse_rgbtobw(node: bpy.types.ShaderNodeRGBToBW, out_socket: bpy.types.NodeS
return '((({0}.r * 0.3 + {0}.g * 0.59 + {0}.b * 0.11) / 3.0) * 2.5)'.format(col)
def parse_sephsv(node: bpy.types.ShaderNodeSeparateHSV, out_socket: bpy.types.NodeSocket) -> floatstr:
# TODO
return '0.0'
def parse_sephsv(node: bpy.types.ShaderNodeSeparateHSV, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr:
state.curshader.add_function(c_functions.str_hue_sat)
hsv_var = c.node_name(node.name) + '_hsv'
state.curshader.write(f'const vec3 {hsv_var} = rgb_to_hsv({c.parse_vector_input(node.inputs["Color"])}.rgb);')
if out_socket == node.outputs[0]:
return f'{hsv_var}.x'
elif out_socket == node.outputs[1]:
return f'{hsv_var}.y'
elif out_socket == node.outputs[2]:
return f'{hsv_var}.z'
def parse_seprgb(node: bpy.types.ShaderNodeSeparateRGB, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr:

View file

@ -1,6 +1,7 @@
import bpy
from typing import Union
import arm.log as log
import arm.material.cycles as c
import arm.material.cycles_functions as c_functions
from arm.material.parser_state import ParserState, ParserContext
@ -213,6 +214,8 @@ def parse_texcoord(node: bpy.types.ShaderNodeTexCoord, out_socket: bpy.types.Nod
if out_socket == node.outputs[0]: # Generated - bounds
return 'bposition'
elif out_socket == node.outputs[1]: # Normal
if state.context == ParserContext.WORLD:
return '-n'
return 'n'
elif out_socket == node.outputs[2]: # UV
state.con.add_elem('tex', 'short2norm')
@ -272,28 +275,36 @@ def parse_layerweight(node: bpy.types.ShaderNodeLayerWeight, out_socket: bpy.typ
def parse_lightpath(node: bpy.types.ShaderNodeLightPath, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr:
if out_socket == node.outputs[0]: # Is Camera Ray
# https://github.com/blender/blender/blob/master/source/blender/gpu/shaders/material/gpu_shader_material_light_path.glsl
if out_socket == node.outputs['Is Camera Ray']:
return '1.0'
elif out_socket == node.outputs[1]: # Is Shadow Ray
elif out_socket == node.outputs['Is Shadow Ray']:
return '0.0'
elif out_socket == node.outputs[2]: # Is Diffuse Ray
elif out_socket == node.outputs['Is Diffuse Ray']:
return '1.0'
elif out_socket == node.outputs[3]: # Is Glossy Ray
elif out_socket == node.outputs['Is Glossy Ray']:
return '1.0'
elif out_socket == node.outputs[4]: # Is Singular Ray
elif out_socket == node.outputs['Is Singular Ray']:
return '0.0'
elif out_socket == node.outputs[5]: # Is Reflection Ray
elif out_socket == node.outputs['Is Reflection Ray']:
return '0.0'
elif out_socket == node.outputs[6]: # Is Transmission Ray
elif out_socket == node.outputs['Is Transmission Ray']:
return '0.0'
elif out_socket == node.outputs[7]: # Ray Length
elif out_socket == node.outputs['Ray Length']:
return '1.0'
elif out_socket == node.outputs['Ray Depth']:
return '0.0'
elif out_socket == node.outputs[8]: # Ray Depth
elif out_socket == node.outputs['Diffuse Depth']:
return '0.0'
elif out_socket == node.outputs[9]: # Transparent Depth
elif out_socket == node.outputs['Glossy Depth']:
return '0.0'
elif out_socket == node.outputs[10]: # Transmission Depth
elif out_socket == node.outputs['Transparent Depth']:
return '0.0'
elif out_socket == node.outputs['Transmission Depth']:
return '0.0'
log.warn(f'Light Path node: unsupported output {out_socket.identifier}.')
return '0.0'
def parse_value(node: bpy.types.ShaderNodeValue, out_socket: bpy.types.NodeSocket, state: ParserState) -> floatstr:

View file

@ -266,7 +266,8 @@ def parse_tex_noise(node: bpy.types.ShaderNodeTexNoise, out_socket: bpy.types.No
scale = c.parse_value_input(node.inputs[2])
detail = c.parse_value_input(node.inputs[3])
distortion = c.parse_value_input(node.inputs[4])#
roughness = c.parse_value_input(node.inputs[4])
distortion = c.parse_value_input(node.inputs[5])
# Color
if out_socket == node.outputs[1]:

View file

@ -106,11 +106,14 @@ def parse_mapping(node: bpy.types.ShaderNodeMapping, out_socket: bpy.types.NodeS
def parse_normal(node: bpy.types.ShaderNodeNormal, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
if out_socket == node.outputs[0]:
return c.to_vec3(node.outputs[0].default_value)
elif out_socket == node.outputs[1]: # TODO: is parse_value path preferred?
nor = c.parse_vector_input(node.inputs[0])
return f'dot({c.to_vec3(node.outputs[0].default_value)}, {nor})'
nor1 = c.to_vec3(node.outputs['Normal'].default_value)
if out_socket == node.outputs['Normal']:
return nor1
elif out_socket == node.outputs['Dot']:
nor2 = c.parse_vector_input(node.inputs["Normal"])
return f'dot({nor1}, {nor2})'
def parse_normalmap(node: bpy.types.ShaderNodeNormalMap, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str: