Merge pull request #2097 from armory3d/2.9-AttributeNode
[Blender 2.9] Update attribute node
This commit is contained in:
commit
d0e92b927b
|
@ -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)'
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue