armory/blender/arm/material/cycles.py

1404 lines
53 KiB
Python
Raw Normal View History

2016-12-13 20:06:23 +01:00
#
# This module builds upon Cycles nodes work licensed as
# Copyright 2011-2013 Blender Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
2017-11-05 23:21:37 +01:00
import math
2017-11-20 14:32:36 +01:00
import bpy
import arm.assets
import arm.utils
import arm.make_state
import arm.log
import arm.material.make_texture
import arm.material.mat_state as mat_state
import arm.material.cycles_functions as c_functions
2016-12-13 11:42:00 +01:00
2017-05-24 11:04:15 +02:00
basecol_texname = ''
2017-06-26 23:53:27 +02:00
emission_found = False
2017-10-04 18:24:13 +02:00
particle_info = None # Particle info export
2017-05-24 11:04:15 +02:00
2017-10-03 16:08:29 +02:00
def parse(nodes, con, vert, frag, geom, tesc, tese, parse_surface=True, parse_opacity=True, parse_displacement=True, basecol_only=False):
2016-12-13 11:42:00 +01:00
output_node = node_by_type(nodes, 'OUTPUT_MATERIAL')
if output_node != None:
2017-10-03 16:08:29 +02:00
parse_output(output_node, con, vert, frag, geom, tesc, tese, parse_surface, parse_opacity, parse_displacement, basecol_only)
2016-12-13 11:42:00 +01:00
2017-10-03 16:08:29 +02:00
def parse_output(node, _con, _vert, _frag, _geom, _tesc, _tese, _parse_surface, _parse_opacity, _parse_displacement, _basecol_only):
2016-12-17 15:34:43 +01:00
global parsed # Compute nodes only once
2016-12-13 11:42:00 +01:00
global parents
2017-10-06 19:44:10 +02:00
global normal_parsed
2016-12-17 15:34:43 +01:00
global curshader # Active shader - frag for surface / tese for displacement
2017-05-25 16:48:41 +02:00
global con
2016-12-13 20:06:23 +01:00
global vert
global frag
2016-12-17 15:34:43 +01:00
global geom
global tesc
global tese
2016-12-20 00:39:18 +01:00
global parse_surface
global parse_opacity
2017-10-03 16:08:29 +02:00
global basecol_only
2016-12-21 19:15:51 +01:00
global parsing_basecol
2017-05-24 11:04:15 +02:00
global basecol_texname
2017-06-26 23:53:27 +02:00
global emission_found
2017-10-04 18:24:13 +02:00
global particle_info
2017-11-07 02:26:03 +01:00
global sample_bump
global sample_bump_res
2017-05-25 16:48:41 +02:00
con = _con
2016-12-13 20:06:23 +01:00
vert = _vert
frag = _frag
2016-12-17 15:34:43 +01:00
geom = _geom
tesc = _tesc
tese = _tese
2016-12-20 00:39:18 +01:00
parse_surface = _parse_surface
parse_opacity = _parse_opacity
2017-10-03 16:08:29 +02:00
basecol_only = _basecol_only
2016-12-21 19:15:51 +01:00
parsing_basecol = False
2017-05-24 11:04:15 +02:00
basecol_texname = ''
2017-06-26 23:53:27 +02:00
emission_found = False
2017-10-04 18:24:13 +02:00
particle_info = {}
particle_info['index'] = False
particle_info['age'] = False
particle_info['lifetime'] = False
particle_info['location'] = False
particle_info['size'] = False
particle_info['velocity'] = False
particle_info['angular_velocity'] = False
2017-11-07 02:26:03 +01:00
sample_bump = False
sample_bump_res = ''
2016-12-17 15:34:43 +01:00
# Surface
2016-12-20 00:39:18 +01:00
if parse_surface or parse_opacity:
2017-12-05 12:25:12 +01:00
parsed = {}
2016-12-17 15:34:43 +01:00
parents = []
2017-10-06 19:44:10 +02:00
normal_parsed = False
2016-12-17 15:34:43 +01:00
curshader = frag
2016-12-20 00:39:18 +01:00
2018-05-19 19:29:14 +02:00
out_basecol, out_roughness, out_metallic, out_occlusion, out_specular, out_opacity = parse_shader_input(node.inputs[0])
2016-12-20 00:39:18 +01:00
if parse_surface:
frag.write('basecol = {0};'.format(out_basecol))
2017-09-09 13:46:32 +02:00
frag.write('roughness = {0};'.format(out_roughness))
frag.write('metallic = {0};'.format(out_metallic))
frag.write('occlusion = {0};'.format(out_occlusion))
2018-05-19 19:29:14 +02:00
frag.write('specular = {0};'.format(out_specular))
2016-12-20 00:39:18 +01:00
if parse_opacity:
frag.write('opacity = {0};'.format(out_opacity))
2016-12-17 15:34:43 +01:00
# Volume
# parse_volume_input(node.inputs[1])
# Displacement
2018-05-07 23:09:38 +02:00
if _parse_displacement and disp_enabled() and node.inputs[2].is_linked:
2017-12-05 12:25:12 +01:00
parsed = {}
2016-12-17 15:34:43 +01:00
parents = []
2017-10-06 19:44:10 +02:00
normal_parsed = False
2018-05-07 23:09:38 +02:00
rpdat = arm.utils.get_rp()
if rpdat.arm_rp_displacement == 'Tessellation' and tese != None:
curshader = tese
else:
curshader = vert
2016-12-17 15:34:43 +01:00
out_disp = parse_displacement_input(node.inputs[2])
2018-05-07 23:09:38 +02:00
curshader.write('float disp = {0};'.format(out_disp))
2016-12-13 11:42:00 +01:00
def parse_group(node, socket): # Entering group
index = socket_index(node, socket)
output_node = node_by_type(node.node_tree.nodes, 'GROUP_OUTPUT')
if output_node == None:
return
inp = output_node.inputs[index]
parents.append(node)
out_group = parse_input(inp)
parents.pop()
return out_group
2017-01-04 00:13:52 +01:00
def parse_group_input(node, socket):
2016-12-13 11:42:00 +01:00
index = socket_index(node, socket)
2017-01-04 00:13:52 +01:00
parent = parents.pop() # Leaving group
2016-12-13 11:42:00 +01:00
inp = parent.inputs[index]
2017-01-04 00:13:52 +01:00
res = parse_input(inp)
parents.append(parent) # Return to group
return res
2016-12-13 11:42:00 +01:00
def parse_input(inp):
if inp.type == 'SHADER':
return parse_shader_input(inp)
elif inp.type == 'RGB':
2016-12-13 20:06:23 +01:00
return parse_vector_input(inp)
2016-12-13 11:42:00 +01:00
elif inp.type == 'RGBA':
2016-12-13 20:06:23 +01:00
return parse_vector_input(inp)
2016-12-13 11:42:00 +01:00
elif inp.type == 'VECTOR':
return parse_vector_input(inp)
elif inp.type == 'VALUE':
return parse_value_input(inp)
def parse_shader_input(inp):
if inp.is_linked:
l = inp.links[0]
2016-12-15 00:18:59 +01:00
if l.from_node.type == 'REROUTE':
return parse_shader_input(l.from_node.inputs[0])
2016-12-13 11:42:00 +01:00
return parse_shader(l.from_node, l.from_socket)
else:
2016-12-13 20:06:23 +01:00
out_basecol = 'vec3(0.8)'
2016-12-13 11:42:00 +01:00
out_roughness = '0.0'
out_metallic = '0.0'
2016-12-13 20:06:23 +01:00
out_occlusion = '1.0'
2018-05-19 19:29:14 +02:00
out_specular = '1.0'
2016-12-20 00:39:18 +01:00
out_opacity = '1.0'
2018-05-19 19:29:14 +02:00
return out_basecol, out_roughness, out_metallic, out_occlusion, out_specular, out_opacity
2016-12-13 11:42:00 +01:00
2017-12-05 12:25:12 +01:00
def parse_shader(node, socket):
2017-08-06 17:36:25 +02:00
global emission_found
2016-12-13 20:06:23 +01:00
out_basecol = 'vec3(0.8)'
out_roughness = '0.0'
out_metallic = '0.0'
out_occlusion = '1.0'
2018-05-19 19:29:14 +02:00
out_specular = '1.0'
2016-12-20 00:39:18 +01:00
out_opacity = '1.0'
2016-12-13 11:42:00 +01:00
2016-12-15 00:18:59 +01:00
if node.type == 'GROUP':
2018-05-21 17:55:26 +02:00
if node.node_tree.name.startswith('Armory PBR'):
2016-12-20 00:39:18 +01:00
if parse_surface:
2017-08-28 11:30:06 +02:00
# Base color
parsing_basecolor(True)
out_basecol = parse_vector_input(node.inputs[0])
parsing_basecolor(False)
# Occlusion
out_occlusion = parse_value_input(node.inputs[2])
# Roughness
out_roughness = parse_value_input(node.inputs[3])
# Metallic
out_metallic = parse_value_input(node.inputs[4])
# Normal
if node.inputs[5].is_linked and node.inputs[5].links[0].from_node.type == 'NORMAL_MAP':
2017-11-20 14:32:36 +01:00
warn(mat_name() + ' - Do not use Normal Map node with Armory PBR, connect Image Texture directly')
2017-08-28 11:30:06 +02:00
parse_normal_map_color_input(node.inputs[5])
# Emission
if node.inputs[6].is_linked or node.inputs[6].default_value != 0.0:
out_emission = parse_value_input(node.inputs[6])
emission_found = True
out_basecol = '({0} + vec3({1} * 100.0))'.format(out_basecol, out_emission)
2016-12-20 00:39:18 +01:00
if parse_opacity:
2017-08-28 11:30:06 +02:00
out_opacity = parse_value_input(node.inputs[1])
2016-12-13 11:42:00 +01:00
else:
return parse_group(node, socket)
elif node.type == 'GROUP_INPUT':
2017-01-04 00:13:52 +01:00
return parse_group_input(node, socket)
2016-12-13 11:42:00 +01:00
elif node.type == 'MIX_SHADER':
2017-03-14 20:43:54 +01:00
prefix = '' if node.inputs[0].is_linked else 'const '
2016-12-13 11:42:00 +01:00
fac = parse_value_input(node.inputs[0])
2016-12-15 00:18:59 +01:00
fac_var = node_name(node.name) + '_fac'
fac_inv_var = node_name(node.name) + '_fac_inv'
2017-03-14 20:43:54 +01:00
curshader.write('{0}float {1} = {2};'.format(prefix, fac_var, fac))
curshader.write('{0}float {1} = 1.0 - {2};'.format(prefix, fac_inv_var, fac_var))
2018-05-19 19:29:14 +02:00
bc1, rough1, met1, occ1, spec1, opac1 = parse_shader_input(node.inputs[1])
bc2, rough2, met2, occ2, spec2, opac2 = parse_shader_input(node.inputs[2])
2016-12-20 00:39:18 +01:00
if parse_surface:
2017-04-26 14:21:22 +02:00
parsing_basecolor(True)
2016-12-20 00:39:18 +01:00
out_basecol = '({0} * {3} + {1} * {2})'.format(bc1, bc2, fac_var, fac_inv_var)
2017-04-26 14:21:22 +02:00
parsing_basecolor(False)
2016-12-20 00:39:18 +01:00
out_roughness = '({0} * {3} + {1} * {2})'.format(rough1, rough2, fac_var, fac_inv_var)
out_metallic = '({0} * {3} + {1} * {2})'.format(met1, met2, fac_var, fac_inv_var)
out_occlusion = '({0} * {3} + {1} * {2})'.format(occ1, occ2, fac_var, fac_inv_var)
2018-05-19 19:29:14 +02:00
out_specular = '({0} * {3} + {1} * {2})'.format(spec1, spec2, fac_var, fac_inv_var)
2016-12-20 00:39:18 +01:00
if parse_opacity:
out_opacity = '({0} * {3} + {1} * {2})'.format(opac1, opac2, fac_var, fac_inv_var)
2016-12-13 11:42:00 +01:00
elif node.type == 'ADD_SHADER':
2018-05-19 19:29:14 +02:00
bc1, rough1, met1, occ1, spec1, opac1 = parse_shader_input(node.inputs[0])
bc2, rough2, met2, occ2, spec2, opac2 = parse_shader_input(node.inputs[1])
2016-12-20 00:39:18 +01:00
if parse_surface:
2017-04-26 14:21:22 +02:00
parsing_basecolor(True)
2016-12-20 00:39:18 +01:00
out_basecol = '({0} + {1})'.format(bc1, bc2)
2017-04-26 14:21:22 +02:00
parsing_basecolor(False)
2016-12-20 00:39:18 +01:00
out_roughness = '({0} * 0.5 + {1} * 0.5)'.format(rough1, rough2)
out_metallic = '({0} * 0.5 + {1} * 0.5)'.format(met1, met2)
out_occlusion = '({0} * 0.5 + {1} * 0.5)'.format(occ1, occ2)
2018-05-19 19:29:14 +02:00
out_specular = '({0} * 0.5 + {1} * 0.5)'.format(spec1, spec2)
2016-12-20 00:39:18 +01:00
if parse_opacity:
out_opacity = '({0} * 0.5 + {1} * 0.5)'.format(opac1, opac2)
2016-12-13 11:42:00 +01:00
2017-06-27 10:55:46 +02:00
elif node.type == 'BSDF_PRINCIPLED':
if parse_surface:
write_normal(node.inputs[16])
parsing_basecolor(True)
out_basecol = parse_vector_input(node.inputs[0])
parsing_basecolor(False)
out_roughness = parse_value_input(node.inputs[7])
out_metallic = parse_value_input(node.inputs[4])
# subsurface = parse_vector_input(node.inputs[1])
# subsurface_radius = parse_vector_input(node.inputs[2])
# subsurface_color = parse_vector_input(node.inputs[3])
2018-05-21 17:55:26 +02:00
out_specular = parse_value_input(node.inputs[5])
2017-06-27 10:55:46 +02:00
# specular_tint = parse_vector_input(node.inputs[6])
# aniso = parse_vector_input(node.inputs[8])
# aniso_rot = parse_vector_input(node.inputs[9])
# sheen = parse_vector_input(node.inputs[10])
# sheen_tint = parse_vector_input(node.inputs[11])
# clearcoat = parse_vector_input(node.inputs[12])
# clearcoat_rough = parse_vector_input(node.inputs[13])
# ior = parse_vector_input(node.inputs[14])
# transmission = parse_vector_input(node.inputs[15])
2016-12-13 11:42:00 +01:00
elif node.type == 'BSDF_DIFFUSE':
2016-12-20 00:39:18 +01:00
if parse_surface:
write_normal(node.inputs[2])
2017-04-26 14:21:22 +02:00
parsing_basecolor(True)
2016-12-20 00:39:18 +01:00
out_basecol = parse_vector_input(node.inputs[0])
2017-04-26 14:21:22 +02:00
parsing_basecolor(False)
2016-12-20 00:39:18 +01:00
out_roughness = parse_value_input(node.inputs[1])
2018-05-19 19:29:14 +02:00
out_specular = '0.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'BSDF_GLOSSY':
2016-12-20 00:39:18 +01:00
if parse_surface:
write_normal(node.inputs[2])
2017-04-26 14:21:22 +02:00
parsing_basecolor(True)
2016-12-20 00:39:18 +01:00
out_basecol = parse_vector_input(node.inputs[0])
2017-04-26 14:21:22 +02:00
parsing_basecolor(False)
2016-12-20 00:39:18 +01:00
out_roughness = parse_value_input(node.inputs[1])
out_metallic = '1.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'AMBIENT_OCCLUSION':
2016-12-20 00:39:18 +01:00
if parse_surface:
# Single channel
out_occlusion = parse_vector_input(node.inputs[0]) + '.r'
2016-12-13 11:42:00 +01:00
elif node.type == 'BSDF_ANISOTROPIC':
2016-12-20 00:39:18 +01:00
if parse_surface:
write_normal(node.inputs[4])
# Revert to glossy
2017-04-26 14:21:22 +02:00
parsing_basecolor(True)
2016-12-20 00:39:18 +01:00
out_basecol = parse_vector_input(node.inputs[0])
2017-04-26 14:21:22 +02:00
parsing_basecolor(False)
2016-12-20 00:39:18 +01:00
out_roughness = parse_value_input(node.inputs[1])
out_metallic = '1.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'EMISSION':
2016-12-20 00:39:18 +01:00
if parse_surface:
# Multiply basecol
2017-04-26 14:21:22 +02:00
parsing_basecolor(True)
2016-12-20 00:39:18 +01:00
out_basecol = parse_vector_input(node.inputs[0])
2017-04-26 14:21:22 +02:00
parsing_basecolor(False)
2017-06-26 23:53:27 +02:00
emission_found = True
2016-12-20 00:39:18 +01:00
strength = parse_value_input(node.inputs[1])
2017-06-27 14:10:26 +02:00
out_basecol = '({0} * ({1} * 100.0))'.format(out_basecol, strength)
2016-12-13 11:42:00 +01:00
elif node.type == 'BSDF_GLASS':
2016-12-20 00:39:18 +01:00
if parse_surface:
write_normal(node.inputs[3])
out_roughness = parse_value_input(node.inputs[1])
if parse_opacity:
out_opacity = '(1.0 - {0}.r)'.format(parse_vector_input(node.inputs[0]))
2016-12-13 11:42:00 +01:00
elif node.type == 'BSDF_HAIR':
pass
elif node.type == 'HOLDOUT':
2016-12-20 00:39:18 +01:00
if parse_surface:
# Occlude
out_occlusion = '0.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'BSDF_REFRACTION':
2016-12-15 22:31:20 +01:00
# write_normal(node.inputs[3])
2016-12-13 11:42:00 +01:00
pass
elif node.type == 'SUBSURFACE_SCATTERING':
2017-05-23 15:01:56 +02:00
if parse_surface:
write_normal(node.inputs[4])
parsing_basecolor(True)
out_basecol = parse_vector_input(node.inputs[0])
parsing_basecolor(False)
2016-12-13 11:42:00 +01:00
elif node.type == 'BSDF_TOON':
2016-12-15 22:31:20 +01:00
# write_normal(node.inputs[3])
2016-12-13 11:42:00 +01:00
pass
elif node.type == 'BSDF_TRANSLUCENT':
2016-12-20 00:39:18 +01:00
if parse_surface:
write_normal(node.inputs[1])
if parse_opacity:
out_opacity = '(1.0 - {0}.r)'.format(parse_vector_input(node.inputs[0]))
2016-12-13 11:42:00 +01:00
elif node.type == 'BSDF_TRANSPARENT':
2016-12-20 00:39:18 +01:00
if parse_opacity:
out_opacity = '(1.0 - {0}.r)'.format(parse_vector_input(node.inputs[0]))
2016-12-13 11:42:00 +01:00
elif node.type == 'BSDF_VELVET':
2016-12-20 00:39:18 +01:00
if parse_surface:
write_normal(node.inputs[2])
2017-04-26 14:21:22 +02:00
parsing_basecolor(True)
2016-12-20 00:39:18 +01:00
out_basecol = parse_vector_input(node.inputs[0])
2017-04-26 14:21:22 +02:00
parsing_basecolor(False)
2016-12-20 00:39:18 +01:00
out_roughness = '1.0'
out_metallic = '1.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'VOLUME_ABSORPTION':
pass
elif node.type == 'VOLUME_SCATTER':
pass
2018-05-19 19:29:14 +02:00
return out_basecol, out_roughness, out_metallic, out_occlusion, out_specular, out_opacity
2016-12-13 11:42:00 +01:00
2016-12-17 15:34:43 +01:00
def parse_displacement_input(inp):
if inp.is_linked:
l = inp.links[0]
if l.from_node.type == 'REROUTE':
return parse_displacement_input(l.from_node.inputs[0])
return parse_value_input(inp)
else:
return None
2018-05-21 17:55:26 +02:00
def parse_vector_input(inp):
2016-12-13 11:42:00 +01:00
if inp.is_linked:
l = inp.links[0]
2016-12-15 00:18:59 +01:00
if l.from_node.type == 'REROUTE':
2018-05-21 17:55:26 +02:00
return parse_vector_input(l.from_node.inputs[0])
2016-12-15 14:28:22 +01:00
res_var = write_result(l)
st = l.from_socket.type
if st == 'RGB' or st == 'RGBA' or st == 'VECTOR':
return res_var
else: # VALUE
return 'vec3({0})'.format(res_var)
2016-12-13 11:42:00 +01:00
else:
2016-12-15 00:18:59 +01:00
if inp.type == 'VALUE': # Unlinked reroute
2017-11-20 14:32:36 +01:00
return to_vec3([0.0, 0.0, 0.0])
2016-12-15 00:18:59 +01:00
else:
2017-11-20 14:32:36 +01:00
if mat_batch() and inp.is_uniform:
return to_uniform(inp)
2017-03-14 20:43:54 +01:00
else:
2017-11-20 14:32:36 +01:00
return to_vec3(inp.default_value)
2016-12-13 11:42:00 +01:00
def parse_rgb(node, socket):
2016-12-15 00:18:59 +01:00
if node.type == 'GROUP':
2016-12-13 11:42:00 +01:00
return parse_group(node, socket)
elif node.type == 'GROUP_INPUT':
2017-01-04 00:13:52 +01:00
return parse_group_input(node, socket)
2016-12-13 11:42:00 +01:00
elif node.type == 'ATTRIBUTE':
2016-12-17 23:48:18 +01:00
# Vcols only for now
# node.attribute_name
2017-05-25 16:48:41 +02:00
con.add_elem('col', 3)
2016-12-19 01:25:22 +01:00
return 'vcolor'
2016-12-13 11:42:00 +01:00
elif node.type == 'RGB':
2017-11-20 14:32:36 +01:00
return to_vec3(socket.default_value)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_BRICK':
2018-05-21 17:55:26 +02:00
curshader.add_function(c_functions.str_tex_brick)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
col1 = parse_vector_input(node.inputs[1])
col2 = parse_vector_input(node.inputs[2])
col3 = parse_vector_input(node.inputs[3])
scale = parse_value_input(node.inputs[4])
return 'tex_brick({0} * {4}, {1}, {2}, {3})'.format(co, col1, col2, col3, scale)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_CHECKER':
2017-04-22 15:08:44 +02:00
curshader.add_function(c_functions.str_tex_checker)
2016-12-15 00:18:59 +01:00
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
2018-05-21 17:55:26 +02:00
co = 'bposition'
2016-12-13 20:06:23 +01:00
col1 = parse_vector_input(node.inputs[1])
col2 = parse_vector_input(node.inputs[2])
scale = parse_value_input(node.inputs[3])
2016-12-15 00:18:59 +01:00
return 'tex_checker({0}, {1}, {2}, {3})'.format(co, col1, col2, scale)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_ENVIRONMENT':
2016-12-13 20:06:23 +01:00
# Pass through
2017-11-20 14:32:36 +01:00
return to_vec3([0.0, 0.0, 0.0])
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_GRADIENT':
2016-12-15 00:18:59 +01:00
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
2018-05-21 17:55:26 +02:00
co = 'bposition'
2016-12-13 20:06:23 +01:00
grad = node.gradient_type
if grad == 'LINEAR':
2016-12-15 00:18:59 +01:00
f = '{0}.x'.format(co)
2016-12-13 20:06:23 +01:00
elif grad == 'QUADRATIC':
f = '0.0'
elif grad == 'EASING':
f = '0.0'
elif grad == 'DIAGONAL':
2016-12-15 00:18:59 +01:00
f = '({0}.x + {0}.y) * 0.5'.format(co)
2016-12-13 20:06:23 +01:00
elif grad == 'RADIAL':
2016-12-15 00:18:59 +01:00
f = 'atan({0}.y, {0}.x) / PI2 + 0.5'.format(co)
2016-12-13 20:06:23 +01:00
elif grad == 'QUADRATIC_SPHERE':
f = '0.0'
elif grad == 'SPHERICAL':
2016-12-15 00:18:59 +01:00
f = 'max(1.0 - sqrt({0}.x * {0}.x + {0}.y * {0}.y + {0}.z * {0}.z), 0.0)'.format(co)
2016-12-13 20:06:23 +01:00
return 'vec3(clamp({0}, 0.0, 1.0))'.format(f)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_IMAGE':
2016-12-20 00:39:18 +01:00
# Already fetched
if res_var_name(node, node.outputs[1]) in parsed:
return '{0}.rgb'.format(store_var_name(node))
2017-08-04 11:54:32 +02:00
tex_name = node_name(node.name)
2017-11-20 14:32:36 +01:00
tex = make_texture(node, tex_name)
2016-12-15 23:50:21 +01:00
if tex != None:
2018-03-26 18:04:11 +02:00
curshader.write_textures += 1
2016-12-21 19:15:51 +01:00
to_linear = parsing_basecol and not tex['file'].endswith('.hdr')
2017-10-30 18:37:45 +01:00
res = '{0}.rgb'.format(texture_store(node, tex, tex_name, to_linear))
2018-03-26 18:04:11 +02:00
curshader.write_textures -= 1
2017-10-30 18:37:45 +01:00
return res
2017-02-13 13:23:43 +01:00
elif node.image == None: # Empty texture
tex = {}
tex['name'] = tex_name
tex['file'] = ''
return '{0}.rgb'.format(texture_store(node, tex, tex_name, True))
2016-12-15 23:50:21 +01:00
else:
2017-01-17 15:49:33 +01:00
tex_store = store_var_name(node) # Pink color for missing texture
curshader.write('vec4 {0} = vec4(1.0, 0.0, 1.0, 1.0);'.format(tex_store))
return '{0}.rgb'.format(tex_store)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_MAGIC':
2018-05-21 17:55:26 +02:00
curshader.add_function(c_functions.str_tex_magic)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
scale = parse_value_input(node.inputs[1])
return 'vec3(tex_magic({0} * {1} * 4.0))'.format(co, scale)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_MUSGRAVE':
2018-05-21 17:55:26 +02:00
curshader.add_function(c_functions.str_tex_musgrave)
2016-12-15 00:18:59 +01:00
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
2018-05-21 17:55:26 +02:00
co = 'bposition'
2016-12-15 00:18:59 +01:00
scale = parse_value_input(node.inputs[1])
# detail = parse_value_input(node.inputs[2])
# distortion = parse_value_input(node.inputs[3])
2018-05-21 17:55:26 +02:00
return 'vec3(tex_musgrave_f({0} * {1} * 0.5))'.format(co, scale)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_NOISE':
2018-05-21 17:55:26 +02:00
curshader.add_function(c_functions.str_tex_noise)
assets_add(get_sdk_path() + '/armory/Assets/' + 'noise256.png')
assets_add_embedded_data('noise256.png')
curshader.add_uniform('sampler2D snoise256', link='_noise256')
2017-04-22 15:08:44 +02:00
curshader.add_function(c_functions.str_tex_noise)
2016-12-15 00:18:59 +01:00
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
2018-05-21 17:55:26 +02:00
co = 'bposition'
2016-12-15 00:18:59 +01:00
scale = parse_value_input(node.inputs[1])
2016-12-13 20:06:23 +01:00
# detail = parse_value_input(node.inputs[2])
# distortion = parse_value_input(node.inputs[3])
2016-12-15 00:18:59 +01:00
# Slow..
2017-01-04 00:13:52 +01:00
return 'vec3(tex_noise({0} * {1}), tex_noise({0} * {1} + 0.33), tex_noise({0} * {1} + 0.66))'.format(co, scale)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_POINTDENSITY':
2016-12-13 20:06:23 +01:00
# Pass through
2017-11-20 14:32:36 +01:00
return to_vec3([0.0, 0.0, 0.0])
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_SKY':
2016-12-13 20:06:23 +01:00
# Pass through
2017-11-20 14:32:36 +01:00
return to_vec3([0.0, 0.0, 0.0])
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_VORONOI':
2017-04-22 15:08:44 +02:00
curshader.add_function(c_functions.str_tex_voronoi)
2018-05-21 17:55:26 +02:00
assets_add(get_sdk_path() + '/armory/Assets/' + 'noise256.png')
assets_add_embedded_data('noise256.png')
curshader.add_uniform('sampler2D snoise256', link='_noise256')
2016-12-15 00:18:59 +01:00
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
2018-05-21 17:55:26 +02:00
co = 'bposition'
2016-12-15 00:18:59 +01:00
scale = parse_value_input(node.inputs[1])
if node.coloring == 'INTENSITY':
2018-05-21 17:55:26 +02:00
return 'vec3(tex_voronoi({0} * {1}).a)'.format(co, scale)
2016-12-15 00:18:59 +01:00
else: # CELLS
2018-05-21 17:55:26 +02:00
return 'tex_voronoi({0} * {1}).rgb'.format(co, scale)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_WAVE':
2018-05-21 17:55:26 +02:00
curshader.add_function(c_functions.str_tex_wave)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
scale = parse_value_input(node.inputs[1])
return 'vec3(tex_wave_f({0} * {1}))'.format(co, scale)
2016-12-13 11:42:00 +01:00
elif node.type == 'BRIGHTCONTRAST':
2016-12-13 20:06:23 +01:00
out_col = parse_vector_input(node.inputs[0])
bright = parse_value_input(node.inputs[1])
contr = parse_value_input(node.inputs[2])
2018-05-21 17:55:26 +02:00
curshader.add_function(c_functions.str_brightcontrast)
2016-12-13 20:06:23 +01:00
return 'brightcontrast({0}, {1}, {2})'.format(out_col, bright, contr)
2016-12-13 11:42:00 +01:00
elif node.type == 'GAMMA':
2016-12-13 20:06:23 +01:00
out_col = parse_vector_input(node.inputs[0])
gamma = parse_value_input(node.inputs[1])
return 'pow({0}, vec3({1}))'.format(out_col, gamma)
2016-12-13 11:42:00 +01:00
elif node.type == 'HUE_SAT':
2017-04-22 15:08:44 +02:00
curshader.add_function(c_functions.str_hsv_to_rgb)
2017-03-20 01:56:46 +01:00
hue = parse_value_input(node.inputs[0])
sat = parse_value_input(node.inputs[1])
val = parse_value_input(node.inputs[2])
# fac = parse_value_input(node.inputs[3])
# col = parse_vector_input(node.inputs[4])
return 'hsv_to_rgb(vec3({0}, {1}, {2}))'.format(hue, sat, val)
2016-12-13 11:42:00 +01:00
elif node.type == 'INVERT':
2016-12-13 20:06:23 +01:00
fac = parse_value_input(node.inputs[0])
out_col = parse_vector_input(node.inputs[1])
return 'mix({0}, vec3(1.0) - ({0}), {1})'.format(out_col, fac)
2016-12-13 11:42:00 +01:00
elif node.type == 'MIX_RGB':
2016-12-13 20:06:23 +01:00
fac = parse_value_input(node.inputs[0])
2016-12-15 00:18:59 +01:00
fac_var = node_name(node.name) + '_fac'
2016-12-17 15:34:43 +01:00
curshader.write('float {0} = {1};'.format(fac_var, fac))
2018-05-21 17:55:26 +02:00
col1 = parse_vector_input(node.inputs[1])
col2 = parse_vector_input(node.inputs[2])
2016-12-13 20:06:23 +01:00
blend = node.blend_type
if blend == 'MIX':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var)
2016-12-13 20:06:23 +01:00
elif blend == 'ADD':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, {0} + {1}, {2})'.format(col1, col2, fac_var)
2016-12-13 20:06:23 +01:00
elif blend == 'MULTIPLY':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, {0} * {1}, {2})'.format(col1, col2, fac_var)
2016-12-13 20:06:23 +01:00
elif blend == 'SUBTRACT':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, {0} - {1}, {2})'.format(col1, col2, fac_var)
2016-12-13 20:06:23 +01:00
elif blend == 'SCREEN':
2016-12-15 00:18:59 +01:00
out_col = '(vec3(1.0) - (vec3(1.0 - {2}) + {2} * (vec3(1.0) - {1})) * (vec3(1.0) - {0}))'.format(col1, col2, fac_var)
2016-12-13 20:06:23 +01:00
elif blend == 'DIVIDE':
2016-12-15 00:18:59 +01:00
out_col = '(vec3((1.0 - {2}) * {0} + {2} * {0} / {1}))'.format(col1, col2, fac_var)
2016-12-13 20:06:23 +01:00
elif blend == 'DIFFERENCE':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, abs({0} - {1}), {2})'.format(col1, col2, fac_var)
2016-12-13 20:06:23 +01:00
elif blend == 'DARKEN':
2016-12-15 00:18:59 +01:00
out_col = 'min({0}, {1} * {2})'.format(col1, col2, fac_var)
2016-12-13 20:06:23 +01:00
elif blend == 'LIGHTEN':
2016-12-15 00:18:59 +01:00
out_col = 'max({0}, {1} * {2})'.format(col1, col2, fac_var)
2016-12-13 20:06:23 +01:00
elif blend == 'OVERLAY':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
2016-12-13 20:06:23 +01:00
elif blend == 'DODGE':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
2016-12-13 20:06:23 +01:00
elif blend == 'BURN':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
2016-12-13 20:06:23 +01:00
elif blend == 'HUE':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
2016-12-13 20:06:23 +01:00
elif blend == 'SATURATION':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
2016-12-13 20:06:23 +01:00
elif blend == 'VALUE':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
2016-12-13 20:06:23 +01:00
elif blend == 'COLOR':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
2016-12-13 20:06:23 +01:00
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':
2016-12-15 00:18:59 +01:00
out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix
# out_col = '({0} + {2} * (2.0 * ({1} - vec3(0.5))))'.format(col1, col2, fac_var)
2016-12-13 20:06:23 +01:00
if node.use_clamp:
return 'clamp({0}, vec3(0.0), vec3(1.0))'.format(out_col)
else:
return out_col
2016-12-13 11:42:00 +01:00
elif node.type == 'CURVE_RGB':
2016-12-13 20:06:23 +01:00
# Pass throuh
return parse_vector_input(node.inputs[1])
2016-12-13 11:42:00 +01:00
elif node.type == 'BLACKBODY':
2016-12-13 20:06:23 +01:00
# Pass constant
2017-11-20 14:32:36 +01:00
return to_vec3([0.84, 0.38, 0.0])
2016-12-13 11:42:00 +01:00
2016-12-13 20:06:23 +01:00
elif node.type == 'VALTORGB': # ColorRamp
fac = parse_value_input(node.inputs[0])
2016-12-15 00:18:59 +01:00
interp = node.color_ramp.interpolation
2016-12-13 20:06:23 +01:00
elems = node.color_ramp.elements
if len(elems) == 1:
2017-11-20 14:32:36 +01:00
return to_vec3(elems[0].color)
2016-12-15 00:18:59 +01:00
if interp == 'CONSTANT':
fac_var = node_name(node.name) + '_fac'
2016-12-17 15:34:43 +01:00
curshader.write('float {0} = {1};'.format(fac_var, fac))
2016-12-15 00:18:59 +01:00
# Get index
out_i = '0'
for i in range(1, len(elems)):
2016-12-15 14:28:22 +01:00
out_i += ' + ({0} > {1} ? 1 : 0)'.format(fac_var, elems[i].position)
2016-12-15 00:18:59 +01:00
# Write cols array
cols_var = node_name(node.name) + '_cols'
2016-12-17 15:34:43 +01:00
curshader.write('vec3 {0}[{1}];'.format(cols_var, len(elems)))
2016-12-15 00:18:59 +01:00
for i in range(0, len(elems)):
2016-12-17 15:34:43 +01:00
curshader.write('{0}[{1}] = vec3({2}, {3}, {4});'.format(cols_var, i, elems[i].color[0], elems[i].color[1], elems[i].color[2]))
2016-12-15 00:18:59 +01:00
return '{0}[{1}]'.format(cols_var, out_i)
else: # Linear, .. - 2 elems only, end pos assumed to be 1
# float f = clamp((pos - start) * (1.0 / (1.0 - start)), 0.0, 1.0);
2017-11-20 14:32:36 +01:00
return 'mix({0}, {1}, clamp(({2} - {3}) * (1.0 / (1.0 - {3})), 0.0, 1.0))'.format(to_vec3(elems[0].color), to_vec3(elems[1].color), fac, elems[0].position)
2016-12-13 11:42:00 +01:00
elif node.type == 'COMBHSV':
2016-12-13 20:06:23 +01:00
# Pass constant
2017-11-20 14:32:36 +01:00
return to_vec3([0.0, 0.0, 0.0])
2016-12-13 11:42:00 +01:00
elif node.type == 'COMBRGB':
2016-12-13 20:06:23 +01:00
r = parse_value_input(node.inputs[0])
g = parse_value_input(node.inputs[1])
b = parse_value_input(node.inputs[2])
return 'vec3({0}, {1}, {2})'.format(r, g, b)
2016-12-13 11:42:00 +01:00
elif node.type == 'WAVELENGTH':
2017-09-01 15:24:46 +02:00
curshader.add_function(c_functions.str_wavelength_to_rgb)
wl = parse_value_input(node.inputs[0])
# Roughly map to cycles - 450 to 600 nanometers
return 'wavelength_to_rgb(({0} - 450.0) / 150.0)'.format(wl)
2016-12-13 11:42:00 +01:00
def parse_vector(node, socket):
2017-10-04 18:24:13 +02:00
global particle_info
2017-11-07 02:26:03 +01:00
global sample_bump
global sample_bump_res
2016-12-13 11:42:00 +01:00
2016-12-15 00:18:59 +01:00
if node.type == 'GROUP':
2016-12-13 11:42:00 +01:00
return parse_group(node, socket)
elif node.type == 'GROUP_INPUT':
2017-01-04 00:13:52 +01:00
return parse_group_input(node, socket)
2016-12-13 11:42:00 +01:00
elif node.type == 'ATTRIBUTE':
2016-12-19 01:25:22 +01:00
# UVMaps only for now
2017-05-25 16:48:41 +02:00
con.add_elem('tex', 2)
2017-11-20 14:32:36 +01:00
mat = mat_get_material()
mat_users = mat_get_material_users()
2016-12-20 00:39:18 +01:00
if mat_users != None and mat in mat_users:
2016-12-19 01:25:22 +01:00
mat_user = mat_users[mat][0]
if hasattr(mat_user.data, 'uv_layers'): # No uvlayers for Curve
lays = mat_user.data.uv_layers
# Second uvmap referenced
if len(lays) > 1 and node.attribute_name == lays[1].name:
2017-05-25 16:48:41 +02:00
con.add_elem('tex1', 2)
2018-05-21 17:55:26 +02:00
return 'vec3(texCoord1.xy, 0.0)'
return 'vec3(texCoord.xy, 0.0)'
2016-12-13 11:42:00 +01:00
elif node.type == 'CAMERA':
2016-12-13 20:06:23 +01:00
# View Vector
2017-03-14 20:43:54 +01:00
return 'vVec'
2016-12-13 11:42:00 +01:00
elif node.type == 'NEW_GEOMETRY':
2016-12-13 20:06:23 +01:00
if socket == node.outputs[0]: # Position
return 'wposition'
elif socket == node.outputs[1]: # Normal
return 'n'
elif socket == node.outputs[2]: # Tangent
return 'vec3(0.0)'
elif socket == node.outputs[3]: # True Normal
return 'n'
elif socket == node.outputs[4]: # Incoming
2017-03-14 20:43:54 +01:00
return 'vVec'
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[5]: # Parametric
2017-09-01 23:34:29 +02:00
return 'mposition'
2016-12-13 11:42:00 +01:00
elif node.type == 'HAIR_INFO':
2016-12-13 20:06:23 +01:00
return 'vec3(0.0)' # Tangent Normal
2016-12-13 11:42:00 +01:00
elif node.type == 'OBJECT_INFO':
2016-12-13 20:06:23 +01:00
return 'wposition'
2016-12-13 11:42:00 +01:00
elif node.type == 'PARTICLE_INFO':
2016-12-13 20:06:23 +01:00
if socket == node.outputs[3]: # Location
2017-10-04 18:24:13 +02:00
particle_info['location'] = True
2017-11-20 14:32:36 +01:00
return 'p_location' if mat_get_material().arm_particle == 'gpu' else 'vec3(0.0)'
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[5]: # Velocity
2017-10-04 18:24:13 +02:00
particle_info['velocity'] = True
2017-11-20 14:32:36 +01:00
return 'p_velocity' if mat_get_material().arm_particle == 'gpu' else 'vec3(0.0)'
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[6]: # Angular Velocity
2017-10-04 18:24:13 +02:00
particle_info['angular_velocity'] = True
2016-12-13 20:06:23 +01:00
return 'vec3(0.0)'
2016-12-13 11:42:00 +01:00
elif node.type == 'TANGENT':
2016-12-13 20:06:23 +01:00
return 'vec3(0.0)'
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_COORD':
2016-12-13 20:06:23 +01:00
#obj = node.object
#dupli = node.from_dupli
2018-05-21 17:55:26 +02:00
if socket == node.outputs[0]: # Generated - bounds
return 'bposition'
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[1]: # Normal
2018-05-21 17:55:26 +02:00
return 'n'
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[2]: # UV
2017-05-25 16:48:41 +02:00
con.add_elem('tex', 2)
2018-05-21 17:55:26 +02:00
return 'vec3(texCoord.x, 1.0 - texCoord.y, 0.0)'
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[3]: # Object
2018-05-21 17:55:26 +02:00
return 'mposition'
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[4]: # Camera
2018-05-21 17:55:26 +02:00
return 'vec3(0.0)' # 'vposition'
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[5]: # Window
2018-05-21 17:55:26 +02:00
return 'vec3(0.0)' # 'wvpposition'
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[6]: # Reflection
2018-05-21 17:55:26 +02:00
return 'vec3(0.0)'
2016-12-13 11:42:00 +01:00
elif node.type == 'UVMAP':
2016-12-13 20:06:23 +01:00
#map = node.uv_map
#dupli = node.from_dupli
2018-05-21 17:55:26 +02:00
return 'vec3(0.0)'
2016-12-13 11:42:00 +01:00
elif node.type == 'BUMP':
2017-11-07 02:26:03 +01:00
# Interpolation strength
2018-05-07 13:02:24 +02:00
strength = parse_value_input(node.inputs[0])
2017-11-07 02:26:03 +01:00
# Height multiplier
2016-12-13 20:06:23 +01:00
# distance = parse_value_input(node.inputs[1])
2017-11-07 02:26:03 +01:00
sample_bump = True
height = parse_value_input(node.inputs[2])
sample_bump = False
nor = parse_vector_input(node.inputs[3])
if sample_bump_res != '':
if node.invert:
ext = ['1', '2', '3', '4']
else:
ext = ['2', '1', '4', '3']
2018-05-07 13:02:24 +02:00
curshader.write('float {0}_fh1 = {0}_{1} - {0}_{2}; float {0}_fh2 = {0}_{3} - {0}_{4};'.format(sample_bump_res, ext[0], ext[1], ext[2], ext[3]))
curshader.write('{0}_fh1 *= ({1}) * 3.0; {0}_fh2 *= ({1}) * 3.0;'.format(sample_bump_res, strength))
curshader.write('vec3 {0}_a = normalize(vec3(2.0, 0.0, {0}_fh1));'.format(sample_bump_res))
curshader.write('vec3 {0}_b = normalize(vec3(0.0, 2.0, {0}_fh2));'.format(sample_bump_res))
res = 'normalize(mat3({0}_a, {0}_b, normalize(vec3({0}_fh1, {0}_fh2, 2.0))) * n)'.format(sample_bump_res)
2017-11-07 02:26:03 +01:00
sample_bump_res = ''
else:
res = 'n'
return res
2016-12-13 11:42:00 +01:00
elif node.type == 'MAPPING':
2017-08-22 10:43:33 +02:00
out = parse_vector_input(node.inputs[0])
2017-11-05 23:21:37 +01:00
# ZYX rotation, Z axis for now..
if node.rotation[2] != 0.0:
a = node.rotation[2]
2018-05-21 17:55:26 +02:00
out = 'vec3({0}.x * {1} - (1.0 - {0}.y) * {2}, 1.0 - ({0}.x * {2} + (1.0 - {0}.y) * {1}), 0.0)'.format(out, math.cos(a), math.sin(a))
2017-11-05 23:21:37 +01:00
# if node.rotation[1] != 0.0:
# a = node.rotation[1]
2018-05-21 17:55:26 +02:00
# out = 'vec3({0}.x * {1} - {0}.z * {2}, {0}.x * {2} + {0}.z * {1}, 0.0)'.format(out, math.cos(a), math.sin(a))
2017-11-05 23:21:37 +01:00
# if node.rotation[0] != 0.0:
# a = node.rotation[0]
2018-05-21 17:55:26 +02:00
# out = 'vec3({0}.y * {1} - {0}.z * {2}, {0}.y * {2} + {0}.z * {1}, 0.0)'.format(out, math.cos(a), math.sin(a))
2017-08-22 10:43:33 +02:00
if node.scale[0] != 1.0 or node.scale[1] != 1.0 or node.scale[2] != 1.0:
2018-05-21 17:55:26 +02:00
out = '({0} * vec3({1}, {2}, {3}))'.format(out, node.scale[0], node.scale[1], node.scale[2])
2017-08-22 10:43:33 +02:00
if node.translation[0] != 0.0 or node.translation[1] != 0.0 or node.translation[2] != 0.0:
2018-05-21 17:55:26 +02:00
out = '({0} + vec3({1}, {2}, {3}))'.format(out, node.translation[0], node.translation[1], node.translation[2])
2017-11-05 23:21:37 +01:00
if node.use_min:
2018-05-21 17:55:26 +02:00
out = 'max({0}, vec3({1}, {2}, {3}))'.format(out, node.min[0], node.min[1])
2017-11-05 23:21:37 +01:00
if node.use_max:
2018-05-21 17:55:26 +02:00
out = 'min({0}, vec3({1}, {2}, {3}))'.format(out, node.max[0], node.max[1])
return out
2016-12-13 11:42:00 +01:00
elif node.type == 'NORMAL':
2016-12-13 20:06:23 +01:00
if socket == node.outputs[0]:
2017-11-20 14:32:36 +01:00
return to_vec3(node.outputs[0].default_value)
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[1]: # TODO: is parse_value path preferred?
nor = parse_vector_input(node.inputs[0])
2017-11-20 14:32:36 +01:00
return 'vec3(dot({0}, {1}))'.format(to_vec3(node.outputs[0].default_value), nor)
2016-12-13 11:42:00 +01:00
elif node.type == 'NORMAL_MAP':
2016-12-21 19:15:51 +01:00
if curshader == tese:
return parse_vector_input(node.inputs[1])
else:
#space = node.space
#map = node.uv_map
2018-05-07 13:02:24 +02:00
strength = parse_value_input(node.inputs[0])
# Color
parse_normal_map_color_input(node.inputs[1], strength)
2016-12-21 19:15:51 +01:00
return None
2016-12-13 11:42:00 +01:00
elif node.type == 'CURVE_VEC':
2016-12-13 20:06:23 +01:00
# fac = parse_value_input(node.inputs[0])
# Pass throuh
return parse_vector_input(node.inputs[1])
2016-12-13 11:42:00 +01:00
elif node.type == 'VECT_TRANSFORM':
2016-12-13 20:06:23 +01:00
#type = node.vector_type
#conv_from = node.convert_from
#conv_to = node.convert_to
# Pass throuh
return parse_vector_input(node.inputs[0])
2016-12-13 11:42:00 +01:00
elif node.type == 'COMBXYZ':
2016-12-13 20:06:23 +01:00
x = parse_value_input(node.inputs[0])
y = parse_value_input(node.inputs[1])
z = parse_value_input(node.inputs[2])
return 'vec3({0}, {1}, {2})'.format(x, y, z)
2016-12-13 11:42:00 +01:00
elif node.type == 'VECT_MATH':
2016-12-13 20:06:23 +01:00
vec1 = parse_vector_input(node.inputs[0])
vec2 = parse_vector_input(node.inputs[1])
op = node.operation
if op == 'ADD':
return '({0} + {1})'.format(vec1, vec2)
elif op == 'SUBTRACT':
return '({0} - {1})'.format(vec1, vec2)
elif op == 'AVERAGE':
return '(({0} + {1}) / 2.0)'.format(vec1, vec2)
elif op == 'DOT_PRODUCT':
return 'vec3(dot({0}, {1}))'.format(vec1, vec2)
elif op == 'CROSS_PRODUCT':
return 'cross({0}, {1})'.format(vec1, vec2)
elif op == 'NORMALIZE':
return 'normalize({0})'.format(vec1)
2016-12-13 11:42:00 +01:00
2018-05-07 13:02:24 +02:00
def parse_normal_map_color_input(inp, strength=1.0):
2017-10-06 19:44:10 +02:00
global normal_parsed
2017-11-10 15:18:44 +01:00
global frag
2017-10-03 16:08:29 +02:00
if basecol_only:
return
2016-12-17 23:48:18 +01:00
if inp.is_linked == False:
return
2017-10-06 19:44:10 +02:00
if normal_parsed:
return
normal_parsed = True
2018-03-26 18:04:11 +02:00
frag.write_normal += 1
2017-11-20 14:32:36 +01:00
defplus = get_rp_renderer() == 'Deferred Plus'
if not get_arm_export_tangents() or defplus or mat_get_material().arm_decal: # Compute TBN matrix
2017-10-23 16:24:57 +02:00
frag.write('vec3 texn = ({0}) * 2.0 - 1.0;'.format(parse_vector_input(inp)))
2017-12-20 10:19:44 +01:00
frag.add_include('std/normals.glsl')
2017-04-01 10:06:49 +02:00
if defplus:
2017-10-23 16:24:57 +02:00
frag.write('mat3 TBN = cotangentFrame(n, -vVec, g2.xy, g2.zw);')
2017-04-01 10:06:49 +02:00
else:
2017-10-23 16:24:57 +02:00
frag.write('mat3 TBN = cotangentFrame(n, -vVec, texCoord);')
frag.write('n = TBN * normalize(texn);')
2017-04-01 10:06:49 +02:00
else:
2017-10-23 16:24:57 +02:00
frag.write('vec3 n = ({0}) * 2.0 - 1.0;'.format(parse_vector_input(inp)))
2018-05-07 13:02:24 +02:00
frag.write('n.xy *= {0};'.format(strength))
2017-10-24 14:06:42 +02:00
frag.write('n = normalize(TBN * n);')
2017-05-25 16:48:41 +02:00
con.add_elem('tang', 3)
2018-03-26 18:04:11 +02:00
frag.write_normal -= 1
2016-12-17 23:48:18 +01:00
2016-12-13 11:42:00 +01:00
def parse_value_input(inp):
if inp.is_linked:
l = inp.links[0]
2016-12-15 00:18:59 +01:00
if l.from_node.type == 'REROUTE':
return parse_value_input(l.from_node.inputs[0])
2016-12-15 14:28:22 +01:00
res_var = write_result(l)
st = l.from_socket.type
if st == 'RGB' or st == 'RGBA' or st == 'VECTOR':
return '{0}.x'.format(res_var)
else: # VALUE
return res_var
2016-12-13 11:42:00 +01:00
else:
2017-11-20 14:32:36 +01:00
if mat_batch() and inp.is_uniform:
return to_uniform(inp)
2017-03-14 20:43:54 +01:00
else:
2017-11-20 14:32:36 +01:00
return to_vec1(inp.default_value)
2016-12-13 11:42:00 +01:00
def parse_value(node, socket):
2017-10-04 18:24:13 +02:00
global particle_info
2017-11-07 02:26:03 +01:00
global sample_bump
2016-12-13 11:42:00 +01:00
2016-12-15 00:18:59 +01:00
if node.type == 'GROUP':
2016-12-17 23:48:18 +01:00
if node.node_tree.name.startswith('Armory PBR'):
# Displacement
if socket == node.outputs[1]:
2017-08-28 11:30:06 +02:00
return parse_value_input(node.inputs[7])
2016-12-17 23:48:18 +01:00
else:
return None
else:
return parse_group(node, socket)
2016-12-13 11:42:00 +01:00
elif node.type == 'GROUP_INPUT':
2017-01-04 00:13:52 +01:00
return parse_group_input(node, socket)
2016-12-13 11:42:00 +01:00
elif node.type == 'ATTRIBUTE':
2016-12-17 15:34:43 +01:00
# Pass time till drivers are implemented
if node.attribute_name == 'time':
curshader.add_uniform('float time', link='_time')
return 'time'
else:
2017-01-14 12:44:43 +01:00
return '0.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'CAMERA':
2016-12-13 20:06:23 +01:00
# View Z Depth
if socket == node.outputs[1]:
2017-12-20 10:19:44 +01:00
curshader.add_include('std/math.glsl')
2017-11-04 18:35:34 +01:00
curshader.add_uniform('vec2 cameraProj', link='_cameraPlaneProj')
return 'linearize(gl_FragCoord.z, cameraProj)'
2016-12-13 20:06:23 +01:00
# View Distance
else:
2017-11-02 14:01:53 +01:00
curshader.add_uniform('vec3 eye', link='_cameraPosition')
return 'distance(eye, wposition)'
2016-12-13 11:42:00 +01:00
elif node.type == 'FRESNEL':
2016-12-13 20:06:23 +01:00
ior = parse_value_input(node.inputs[0])
#nor = parse_vectorZ_input(node.inputs[1])
return 'pow(1.0 - dotNV, 7.25 / {0})'.format(ior) # max(dotNV, 0.0)
2016-12-13 11:42:00 +01:00
elif node.type == 'NEW_GEOMETRY':
2016-12-13 20:06:23 +01:00
if socket == node.outputs[6]: # Backfacing
return '0.0'
elif socket == node.outputs[7]: # Pointiness
return '0.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'HAIR_INFO':
2016-12-13 20:06:23 +01:00
# Is Strand
# Intercept
# Thickness
2017-01-14 12:44:43 +01:00
return '0.5'
2016-12-13 11:42:00 +01:00
elif node.type == 'LAYER_WEIGHT':
2016-12-13 20:06:23 +01:00
blend = parse_value_input(node.inputs[0])
# nor = parse_vector_input(node.inputs[1])
if socket == node.outputs[0]: # Fresnel
2016-12-15 00:18:59 +01:00
return 'clamp(pow(1.0 - dotNV, (1.0 - {0}) * 10.0), 0.0, 1.0)'.format(blend)
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[1]: # Facing
return '((1.0 - dotNV) * {0})'.format(blend)
2016-12-13 11:42:00 +01:00
elif node.type == 'LIGHT_PATH':
2016-12-13 20:06:23 +01:00
if socket == node.outputs[0]: # Is Camera Ray
return '1.0'
2016-12-21 19:15:51 +01:00
elif socket == node.outputs[1]: # Is Shadow Ray
2016-12-13 20:06:23 +01:00
return '0.0'
2016-12-21 19:15:51 +01:00
elif socket == node.outputs[2]: # Is Diffuse Ray
2016-12-13 20:06:23 +01:00
return '1.0'
2016-12-21 19:15:51 +01:00
elif socket == node.outputs[3]: # Is Glossy Ray
2016-12-13 20:06:23 +01:00
return '1.0'
2016-12-21 19:15:51 +01:00
elif socket == node.outputs[4]: # Is Singular Ray
2016-12-13 20:06:23 +01:00
return '0.0'
2016-12-21 19:15:51 +01:00
elif socket == node.outputs[5]: # Is Reflection Ray
2016-12-13 20:06:23 +01:00
return '0.0'
2016-12-21 19:15:51 +01:00
elif socket == node.outputs[6]: # Is Transmission Ray
2016-12-13 20:06:23 +01:00
return '0.0'
2016-12-21 19:15:51 +01:00
elif socket == node.outputs[7]: # Ray Length
2016-12-13 20:06:23 +01:00
return '0.0'
2016-12-21 19:15:51 +01:00
elif socket == node.outputs[8]: # Ray Depth
2016-12-13 20:06:23 +01:00
return '0.0'
2016-12-21 19:15:51 +01:00
elif socket == node.outputs[9]: # Transparent Depth
2016-12-13 20:06:23 +01:00
return '0.0'
2016-12-21 19:15:51 +01:00
elif socket == node.outputs[10]: # Transmission Depth
2016-12-13 20:06:23 +01:00
return '0.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'OBJECT_INFO':
2017-03-20 01:56:46 +01:00
if socket == node.outputs[1]: # Object Index
curshader.add_uniform('float objectInfoIndex', link='_objectInfoIndex')
return 'objectInfoIndex'
elif socket == node.outputs[2]: # Material Index
curshader.add_uniform('float objectInfoMaterialIndex', link='_objectInfoMaterialIndex')
return 'objectInfoMaterialIndex'
elif socket == node.outputs[3]: # Random
curshader.add_uniform('float objectInfoRandom', link='_objectInfoRandom')
return 'objectInfoRandom'
2016-12-13 11:42:00 +01:00
elif node.type == 'PARTICLE_INFO':
2016-12-13 20:06:23 +01:00
if socket == node.outputs[0]: # Index
2017-10-04 18:24:13 +02:00
particle_info['index'] = True
2017-11-20 14:32:36 +01:00
return 'p_index' if mat_get_material().arm_particle == 'gpu' else '0.0'
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[1]: # Age
2017-10-04 18:24:13 +02:00
particle_info['age'] = True
2017-11-20 14:32:36 +01:00
return 'p_age' if mat_get_material().arm_particle == 'gpu' else '0.0'
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[2]: # Lifetime
2017-10-04 18:24:13 +02:00
particle_info['lifetime'] = True
2017-11-20 14:32:36 +01:00
return 'p_lifetime' if mat_get_material().arm_particle == 'gpu' else '0.0'
2016-12-13 20:06:23 +01:00
elif socket == node.outputs[4]: # Size
2017-10-04 18:24:13 +02:00
particle_info['size'] = True
return '1.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'VALUE':
2017-11-20 14:32:36 +01:00
return to_vec1(node.outputs[0].default_value)
2016-12-13 11:42:00 +01:00
elif node.type == 'WIREFRAME':
2016-12-13 20:06:23 +01:00
#node.use_pixel_size
# size = parse_value_input(node.inputs[0])
return '0.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_BRICK':
2018-05-21 17:55:26 +02:00
curshader.add_function(c_functions.str_tex_brick)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
scale = parse_value_input(node.inputs[4])
return 'tex_brick_f({0} * {1})'.format(co, scale)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_CHECKER':
2017-04-22 15:08:44 +02:00
curshader.add_function(c_functions.str_tex_checker)
2016-12-15 00:18:59 +01:00
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
2018-05-21 17:55:26 +02:00
co = 'bposition'
2016-12-15 00:18:59 +01:00
scale = parse_value_input(node.inputs[3])
2018-05-21 17:55:26 +02:00
res = 'tex_checker_f({0}, {1}).r'.format(co, scale)
2017-11-07 02:26:03 +01:00
if sample_bump:
write_bump(node, res)
return res
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_GRADIENT':
2018-05-21 17:55:26 +02:00
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
grad = node.gradient_type
if grad == 'LINEAR':
f = '{0}.x'.format(co)
elif grad == 'QUADRATIC':
f = '0.0'
elif grad == 'EASING':
f = '0.0'
elif grad == 'DIAGONAL':
f = '({0}.x + {0}.y) * 0.5'.format(co)
elif grad == 'RADIAL':
f = 'atan({0}.y, {0}.x) / PI2 + 0.5'.format(co)
elif grad == 'QUADRATIC_SPHERE':
f = '0.0'
elif grad == 'SPHERICAL':
f = 'max(1.0 - sqrt({0}.x * {0}.x + {0}.y * {0}.y + {0}.z * {0}.z), 0.0)'.format(co)
return '(clamp({0}, 0.0, 1.0))'.format(f)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_IMAGE':
2016-12-20 00:39:18 +01:00
# Already fetched
if res_var_name(node, node.outputs[0]) in parsed:
return '{0}.a'.format(store_var_name(node))
2017-11-20 14:32:36 +01:00
tex_name = safesrc(node.name)
tex = make_texture(node, tex_name)
2016-12-20 00:39:18 +01:00
if tex != None:
2018-03-26 18:04:11 +02:00
curshader.write_textures += 1
2017-10-30 18:37:45 +01:00
res = '{0}.a'.format(texture_store(node, tex, tex_name))
2018-03-26 18:04:11 +02:00
curshader.write_textures -= 1
2017-10-30 18:37:45 +01:00
return res
2016-12-20 00:39:18 +01:00
else:
2017-01-17 15:49:33 +01:00
tex_store = store_var_name(node) # Pink color for missing texture
curshader.write('vec4 {0} = vec4(1.0, 0.0, 1.0, 1.0);'.format(tex_store))
return '{0}.a'.format(tex_store)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_MAGIC':
2018-05-21 17:55:26 +02:00
curshader.add_function(c_functions.str_tex_magic)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
scale = parse_value_input(node.inputs[1])
return 'tex_magic_f({0} * {1} * 4.0)'.format(co, scale)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_MUSGRAVE':
2016-12-15 00:18:59 +01:00
# Fall back to noise
2018-05-21 17:55:26 +02:00
curshader.add_function(c_functions.str_tex_musgrave)
2016-12-15 00:18:59 +01:00
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
2018-05-21 17:55:26 +02:00
co = 'bposition'
2016-12-15 00:18:59 +01:00
scale = parse_value_input(node.inputs[1])
# detail = parse_value_input(node.inputs[2])
# distortion = parse_value_input(node.inputs[3])
2018-05-21 17:55:26 +02:00
return 'tex_musgrave_f({0} * {1} * 0.5)'.format(co, scale)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_NOISE':
2017-04-22 15:08:44 +02:00
curshader.add_function(c_functions.str_tex_noise)
2018-05-21 17:55:26 +02:00
assets_add(get_sdk_path() + '/armory/Assets/' + 'noise256.png')
assets_add_embedded_data('noise256.png')
curshader.add_uniform('sampler2D snoise256', link='_noise256')
2016-12-15 00:18:59 +01:00
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
2018-05-21 17:55:26 +02:00
co = 'bposition'
2016-12-15 00:18:59 +01:00
scale = parse_value_input(node.inputs[1])
# detail = parse_value_input(node.inputs[2])
# distortion = parse_value_input(node.inputs[3])
2017-11-07 02:26:03 +01:00
res = 'tex_noise({0} * {1})'.format(co, scale)
if sample_bump:
write_bump(node, res)
return res
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_POINTDENSITY':
2016-12-13 20:06:23 +01:00
return '0.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_VORONOI':
2017-04-22 15:08:44 +02:00
curshader.add_function(c_functions.str_tex_voronoi)
2018-05-21 17:55:26 +02:00
assets_add(get_sdk_path() + '/armory/Assets/' + 'noise256.png')
assets_add_embedded_data('noise256.png')
curshader.add_uniform('sampler2D snoise256', link='_noise256')
2016-12-15 00:18:59 +01:00
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
2018-05-21 17:55:26 +02:00
co = 'bposition'
2016-12-15 00:18:59 +01:00
scale = parse_value_input(node.inputs[1])
if node.coloring == 'INTENSITY':
2018-05-21 17:55:26 +02:00
return 'tex_voronoi({0} * {1}).a'.format(co, scale)
2016-12-15 00:18:59 +01:00
else: # CELLS
2018-05-21 17:55:26 +02:00
return 'tex_voronoi({0} * {1}).r'.format(co, scale)
2016-12-13 11:42:00 +01:00
elif node.type == 'TEX_WAVE':
2018-05-21 17:55:26 +02:00
curshader.add_function(c_functions.str_tex_wave)
if node.inputs[0].is_linked:
co = parse_vector_input(node.inputs[0])
else:
co = 'bposition'
scale = parse_value_input(node.inputs[1])
return 'tex_wave_f({0} * {1})'.format(co, scale)
2016-12-13 11:42:00 +01:00
elif node.type == 'LIGHT_FALLOFF':
2017-02-22 15:50:19 +01:00
# Constant, linear, quadratic
# Shaders default to quadratic for now
return '1.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'NORMAL':
2016-12-13 20:06:23 +01:00
nor = parse_vector_input(node.inputs[0])
2017-11-20 14:32:36 +01:00
return 'dot({0}, {1})'.format(to_vec3(node.outputs[0].default_value), nor)
2016-12-13 11:42:00 +01:00
2016-12-13 20:06:23 +01:00
elif node.type == 'VALTORGB': # ColorRamp
return '1.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'MATH':
2016-12-13 20:06:23 +01:00
val1 = parse_value_input(node.inputs[0])
val2 = parse_value_input(node.inputs[1])
op = node.operation
if op == 'ADD':
out_val = '({0} + {1})'.format(val1, val2)
elif op == 'SUBTRACT':
out_val = '({0} - {1})'.format(val1, val2)
elif op == 'MULTIPLY':
out_val = '({0} * {1})'.format(val1, val2)
elif op == 'DIVIDE':
out_val = '({0} / {1})'.format(val1, val2)
elif op == 'SINE':
2016-12-15 00:18:59 +01:00
out_val = 'sin({0})'.format(val1)
2016-12-13 20:06:23 +01:00
elif op == 'COSINE':
2016-12-15 00:18:59 +01:00
out_val = 'cos({0})'.format(val1)
2016-12-13 20:06:23 +01:00
elif op == 'TANGENT':
2016-12-15 00:18:59 +01:00
out_val = 'tan({0})'.format(val1)
2016-12-13 20:06:23 +01:00
elif op == 'ARCSINE':
2016-12-15 00:18:59 +01:00
out_val = 'asin({0})'.format(val1)
2016-12-13 20:06:23 +01:00
elif op == 'ARCCOSINE':
2016-12-15 00:18:59 +01:00
out_val = 'acos({0})'.format(val1)
2016-12-13 20:06:23 +01:00
elif op == 'ARCTANGENT':
2016-12-15 00:18:59 +01:00
out_val = 'atan({0})'.format(val1)
2016-12-13 20:06:23 +01:00
elif op == 'POWER':
out_val = 'pow({0}, {1})'.format(val1, val2)
elif op == 'LOGARITHM':
out_val = 'log({0})'.format(val1)
elif op == 'MINIMUM':
out_val = 'min({0}, {1})'.format(val1, val2)
elif op == 'MAXIMUM':
out_val = 'max({0}, {1})'.format(val1, val2)
elif op == 'ROUND':
2016-12-15 00:18:59 +01:00
# out_val = 'round({0})'.format(val1)
out_val = 'floor({0} + 0.5)'.format(val1)
2016-12-13 20:06:23 +01:00
elif op == 'LESS_THAN':
out_val = 'float({0} < {1})'.format(val1, val2)
elif op == 'GREATER_THAN':
out_val = 'float({0} > {1})'.format(val1, val2)
elif op == 'MODULO':
2016-12-15 00:18:59 +01:00
# out_val = 'float({0} % {1})'.format(val1, val2)
out_val = 'mod({0}, {1})'.format(val1, val2)
2016-12-13 20:06:23 +01:00
elif op == 'ABSOLUTE':
out_val = 'abs({0})'.format(val1)
if node.use_clamp:
return 'clamp({0}, 0.0, 1.0)'.format(out_val)
else:
return out_val
2016-12-13 11:42:00 +01:00
elif node.type == 'RGBTOBW':
2016-12-13 20:06:23 +01:00
col = parse_vector_input(node.inputs[0])
return '((({0}.r * 0.3 + {0}.g * 0.59 + {0}.b * 0.11) / 3.0) * 2.5)'.format(col)
2016-12-13 11:42:00 +01:00
elif node.type == 'SEPHSV':
2016-12-13 20:06:23 +01:00
return '0.0'
2016-12-13 11:42:00 +01:00
elif node.type == 'SEPRGB':
2016-12-13 20:06:23 +01:00
col = parse_vector_input(node.inputs[0])
if socket == node.outputs[0]:
return '{0}.r'.format(col)
elif socket == node.outputs[1]:
return '{0}.g'.format(col)
elif socket == node.outputs[2]:
return '{0}.b'.format(col)
2016-12-13 11:42:00 +01:00
elif node.type == 'SEPXYZ':
2016-12-13 20:06:23 +01:00
vec = parse_vector_input(node.inputs[0])
if socket == node.outputs[0]:
return '{0}.x'.format(vec)
elif socket == node.outputs[1]:
return '{0}.y'.format(vec)
elif socket == node.outputs[2]:
return '{0}.z'.format(vec)
2016-12-13 11:42:00 +01:00
elif node.type == 'VECT_MATH':
2016-12-13 20:06:23 +01:00
vec1 = parse_vector_input(node.inputs[0])
vec2 = parse_vector_input(node.inputs[1])
op = node.operation
if op == 'DOT_PRODUCT':
return 'dot({0}, {1})'.format(vec1, vec2)
else:
return '0.0'
2016-12-13 11:42:00 +01:00
2018-05-21 17:55:26 +02:00
##
def write_normal(inp):
if inp.is_linked:
normal_res = parse_vector_input(inp)
if normal_res != None:
curshader.write('n = {0};'.format(normal_res))
def parsing_basecolor(b):
global parsing_basecol
parsing_basecol = b
def res_var_name(node, socket):
return node_name(node.name) + '_' + safesrc(socket.name) + '_res'
def write_result(l):
res_var = res_var_name(l.from_node, l.from_socket)
st = l.from_socket.type
if res_var not in parsed:
parsed[res_var] = True
if st == 'RGB' or st == 'RGBA':
res = parse_rgb(l.from_node, l.from_socket)
if res == None:
return None
curshader.write('vec3 {0} = {1};'.format(res_var, res))
elif st == 'VECTOR':
res = parse_vector(l.from_node, l.from_socket)
if res == None:
return None
curshader.write('vec3 {0} = {1};'.format(res_var, res))
elif st == 'VALUE':
res = parse_value(l.from_node, l.from_socket)
if res == None:
return None
curshader.write('float {0} = {1};'.format(res_var, res))
# Normal map already parsed, return
elif l.from_node.type == 'NORMAL_MAP':
return None
return res_var
def glsl_type(t):
if t == 'RGB' or t == 'RGBA' or t == 'VECTOR':
return 'vec3'
else:
return 'float'
def to_uniform(inp):
uname = safesrc(inp.node.name) + safesrc(inp.name)
curshader.add_uniform(glsl_type(inp.type) + ' ' + uname)
return uname
def store_var_name(node):
return node_name(node.name) + '_store'
def texture_store(node, tex, tex_name, to_linear=False):
global parsing_basecol
global basecol_texname
global sample_bump
global sample_bump_res
mat_bind_texture(tex)
con.add_elem('tex', 2)
curshader.add_uniform('sampler2D {0}'.format(tex_name))
if node.inputs[0].is_linked:
uv_name = parse_vector_input(node.inputs[0])
else:
uv_name = 'texCoord'
tex_store = store_var_name(node)
if mat_texture_grad():
curshader.write('vec4 {0} = textureGrad({1}, {2}.xy, g2.xy, g2.zw);'.format(tex_store, tex_name, uv_name))
else:
curshader.write('vec4 {0} = texture({1}, {2}.xy);'.format(tex_store, tex_name, uv_name))
if sample_bump:
sample_bump_res = tex_store
curshader.write('float {0}_1 = textureOffset({1}, {2}.xy, ivec2(-2, 0)).r;'.format(tex_store, tex_name, uv_name))
curshader.write('float {0}_2 = textureOffset({1}, {2}.xy, ivec2(2, 0)).r;'.format(tex_store, tex_name, uv_name))
curshader.write('float {0}_3 = textureOffset({1}, {2}.xy, ivec2(0, -2)).r;'.format(tex_store, tex_name, uv_name))
curshader.write('float {0}_4 = textureOffset({1}, {2}.xy, ivec2(0, 2)).r;'.format(tex_store, tex_name, uv_name))
sample_bump = False
if to_linear:
curshader.write('{0}.rgb = pow({0}.rgb, vec3(2.2));'.format(tex_store))
if parsing_basecol:
basecol_texname = tex_store
return tex_store
2017-11-07 02:26:03 +01:00
def write_bump(node, res):
global sample_bump
global sample_bump_res
sample_bump_res = store_var_name(node) + '_bump'
# Testing.. get function parts..
ar = res.split('(', 1)
pre = ar[0] + '('
if ',' in ar[1]:
ar2 = ar[1].split(',', 1)
co = ar2[0]
2018-05-07 13:02:24 +02:00
post = ',' + ar2[1]
2017-11-07 02:26:03 +01:00
else:
co = ar[1][:-1]
post = ')'
2018-05-07 13:02:24 +02:00
curshader.write('float {0}_1 = {1}{2} + vec2(-2, 0){3};'.format(sample_bump_res, pre, co, post))
curshader.write('float {0}_2 = {1}{2} + vec2(2, 0){3};'.format(sample_bump_res, pre, co, post))
curshader.write('float {0}_3 = {1}{2} + vec2(0, -2){3};'.format(sample_bump_res, pre, co, post))
curshader.write('float {0}_4 = {1}{2} + vec2(0, 2){3};'.format(sample_bump_res, pre, co, post))
2017-11-07 02:26:03 +01:00
sample_bump = False
2017-11-20 14:32:36 +01:00
def to_vec1(v):
2016-12-13 11:42:00 +01:00
return str(v)
2017-11-20 14:32:36 +01:00
def to_vec3(v):
2016-12-13 11:42:00 +01:00
return 'vec3({0}, {1}, {2})'.format(v[0], v[1], v[2])
2016-12-15 23:50:21 +01:00
def node_by_type(nodes, ntype):
for n in nodes:
if n.type == ntype:
return n
def socket_index(node, socket):
for i in range(0, len(node.outputs)):
if node.outputs[i] == socket:
return i
def node_name(s):
2017-11-20 14:32:36 +01:00
s = safesrc(s)
2016-12-15 23:50:21 +01:00
if len(parents) > 0:
2017-11-20 14:32:36 +01:00
s = safesrc(parents[-1].name) + '_' + s
2017-08-04 11:54:32 +02:00
if '__' in s: # Consecutive _ are reserved
s = s.replace('_', '_x')
2016-12-15 23:50:21 +01:00
return s
2017-11-20 14:32:36 +01:00
##
def get_rp_renderer():
return arm.utils.get_rp().rp_renderer
def get_arm_export_tangents():
return bpy.data.worlds['Arm'].arm_export_tangents
def safesrc(name):
return arm.utils.safesrc(name)
def get_sdk_path():
return arm.utils.get_sdk_path()
2017-11-26 14:45:36 +01:00
def disp_enabled():
return arm.utils.disp_enabled(arm.make_state.target)
2017-11-20 14:32:36 +01:00
def warn(text):
arm.log.warn(text)
def assets_add(path):
arm.assets.add(path)
def assets_add_embedded_data(path):
arm.assets.add_embedded_data(path)
def make_texture(node, name):
return arm.material.make_texture.make(node, name)
def mat_name():
return mat_state.material.name
def mat_batch():
return mat_state.batch
def mat_bind_texture(tex):
mat_state.bind_textures.append(tex)
def mat_texture_grad():
return mat_state.texture_grad
def mat_get_material():
return mat_state.material
def mat_get_material_users():
return mat_state.mat_users