Merge pull request #2097 from armory3d/2.9-AttributeNode

[Blender 2.9] Update attribute node
This commit is contained in:
Lubos Lenco 2021-01-30 19:57:17 +01:00 committed by GitHub
commit d0e92b927b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 98 additions and 22 deletions

View file

@ -644,6 +644,41 @@ def to_vec3(v):
return 'vec3({0}, {1}, {2})'.format(v[0], v[1], v[2])
def cast_value(val: str, from_type: str, to_type: str) -> str:
"""Casts a value that is already parsed in a glsl string to another
value in a string.
vec2 types are not supported (not used in the node editor) and there
is no cast towards int types. If casting from vec3 to vec4, the w
coordinate/alpha channel is filled with a 1.
If this function is called with invalid parameters, a TypeError is
raised.
"""
if from_type == to_type:
return val
if from_type in ('int', 'float'):
if to_type in ('int', 'float'):
return val
elif to_type in ('vec2', 'vec3', 'vec4'):
return f'{to_type}({val})'
elif from_type == 'vec3':
if to_type == 'float':
return rgb_to_bw(val)
elif to_type == 'vec4':
return f'vec4({val}, 1.0)'
elif from_type == 'vec4':
if to_type == 'float':
return rgb_to_bw(val)
elif to_type == 'vec3':
return f'{val}.xyz'
raise TypeError("Invalid type cast in shader!")
def rgb_to_bw(res_var: vec3str) -> floatstr:
return f'((({res_var}.r * 0.3 + {res_var}.g * 0.59 + {res_var}.b * 0.11) / 3.0) * 2.5)'

View file

@ -1,6 +1,8 @@
import bpy
from typing import Union
import bpy
import mathutils
import arm.log as log
import arm.material.cycles as c
import arm.material.cycles_functions as c_functions
@ -10,42 +12,81 @@ import arm.utils
def parse_attribute(node: bpy.types.ShaderNodeAttribute, out_socket: bpy.types.NodeSocket, state: ParserState) -> Union[floatstr, vec3str]:
# Color
if out_socket == node.outputs[0]:
# Vertex colors only for now
state.con.add_elem('col', 'short4norm')
return 'vcolor'
out_type = 'float' if out_socket.type == 'VALUE' else 'vec3'
# Vector
elif out_socket == node.outputs[1]:
# UV maps only for now
state.con.add_elem('tex', 'short2norm')
if node.attribute_name == 'time':
state.curshader.add_uniform('float time', link='_time')
if out_socket == node.outputs[3]:
return '1.0'
return c.cast_value('time', from_type='float', to_type=out_type)
# UV maps (higher priority) and vertex colors
if node.attribute_type == 'GEOMETRY':
# Alpha output. Armory doesn't support vertex colors with alpha
# values yet and UV maps don't have an alpha channel
if out_socket == node.outputs[3]:
return '1.0'
# UV maps
mat = c.mat_get_material()
mat_users = c.mat_get_material_users()
if mat_users is not None and mat in mat_users:
mat_user = mat_users[mat][0]
# No UV layers for Curve
# Curves don't have uv layers, so check that first
if hasattr(mat_user.data, 'uv_layers'):
lays = mat_user.data.uv_layers
# First UV map referenced
if node.attribute_name == lays[0].name:
state.con.add_elem('tex', 'short2norm')
return c.cast_value('vec3(texCoord.x, 1.0 - texCoord.y, 0.0)', from_type='vec3', to_type=out_type)
# Second UV map referenced
if len(lays) > 1 and node.attribute_name == lays[1].name:
elif len(lays) > 1 and node.attribute_name == lays[1].name:
state.con.add_elem('tex1', 'short2norm')
return 'vec3(texCoord1.x, 1.0 - texCoord1.y, 0.0)'
return c.cast_value('vec3(texCoord1.x, 1.0 - texCoord1.y, 0.0)', from_type='vec3', to_type=out_type)
return 'vec3(texCoord.x, 1.0 - texCoord.y, 0.0)'
# Vertex colors
# TODO: support multiple vertex color sets
state.con.add_elem('col', 'short4norm')
return c.cast_value('vcolor', from_type='vec3', to_type=out_type)
# Fac
else:
if node.attribute_name == 'time':
state.curshader.add_uniform('float time', link='_time')
return 'time'
# Check object properties
# see https://developer.blender.org/rB6fdcca8de6 for reference
mat = c.mat_get_material()
mat_users = c.mat_get_material_users()
if mat_users is not None and mat in mat_users:
# Use first material user for now...
mat_user = mat_users[mat][0]
# Return 0.0 till drivers are implemented
else:
return '0.0'
val = None
# Custom properties first
if node.attribute_name in mat_user:
val = mat_user[node.attribute_name]
# Blender properties
elif hasattr(mat_user, node.attribute_name):
val = getattr(mat_user, node.attribute_name)
if val is not None:
if isinstance(val, float):
return c.cast_value(str(val), from_type='float', to_type=out_type)
elif isinstance(val, int):
return c.cast_value(str(val), from_type='int', to_type=out_type)
elif isinstance(val, mathutils.Vector) and len(val) <= 4:
out = val.to_4d()
if out_socket == node.outputs[3]:
return c.to_vec1(out[3])
return c.cast_value(c.to_vec3(out), from_type='vec3', to_type=out_type)
# Default values, attribute name did not match
if out_socket == node.outputs[3]:
return '1.0'
return c.cast_value('0.0', from_type='float', to_type=out_type)
def parse_rgb(node: bpy.types.ShaderNodeRGB, out_socket: bpy.types.NodeSocket, state: ParserState) -> vec3str: