New material bind system

This commit is contained in:
Lubos Lenco 2017-05-25 16:48:41 +02:00
parent 59c043ea22
commit 9d9f39aeb4
20 changed files with 164 additions and 132 deletions

View file

@ -34,14 +34,9 @@ def add(file):
def add_khafile_def(d):
global khafile_defs
global khafile_defs_last
if d not in khafile_defs:
khafile_defs.append(d)
wrd = bpy.data.worlds['Arm']
if not wrd.arm_recompile_trigger and d not in khafile_defs_last:
wrd.arm_recompile_trigger = True
def add_embedded_data(file):
global embedded_data
if file not in embedded_data:

View file

@ -2068,8 +2068,6 @@ class ArmoryExporter:
o['cast_shadow'] = objref.cycles.cast_shadow
o['near_plane'] = objref.lamp_clip_start
if (o['near_plane'] <= 0.11 and o['type'] == 'point'):
o['near_plane'] /= 10 # Prevent acne on close surfaces
o['far_plane'] = objref.lamp_clip_end
o['fov'] = objref.lamp_fov
o['shadows_bias'] = objref.lamp_shadows_bias
@ -2090,6 +2088,8 @@ class ArmoryExporter:
if objref.lamp_omni_shadows_cubemap:
o['shadowmap_cube'] = True
o['shadows_bias'] *= 4.0
# if (o['near_plane'] <= 0.11:
# o['near_plane'] /= 10 # Prevent acne on close surfaces
# Parse nodes
# Emission only for now
@ -2265,17 +2265,18 @@ class ArmoryExporter:
tang_export = False
vcol_export = False
vs_str = ''
for elem in sd['vertex_structure']:
if len(vs_str) > 0:
vs_str += ','
vs_str += elem['name']
if elem['name'] == 'tang':
tang_export = True
elif elem['name'] == 'tex':
uv_export = True
elif elem['name'] == 'col':
vcol_export = True
for con in sd['contexts']:
for elem in con['vertex_structure']:
if len(vs_str) > 0:
vs_str += ','
vs_str += elem['name']
if elem['name'] == 'tang':
tang_export = True
elif elem['name'] == 'tex':
uv_export = True
elif elem['name'] == 'col':
vcol_export = True
# TODO: use array and remove duplis to ensure correctness
material.vertex_structure = vs_str
if (material.export_tangents != tang_export) or \
@ -2495,19 +2496,20 @@ class ArmoryExporter:
self.export_materials()
# Ensure same vertex structure for object materials
for bobject in self.scene.objects:
if len(bobject.material_slots) > 1:
mat = bobject.material_slots[0].material
if mat == None:
continue
vs = mat.vertex_structure
for i in range(len(bobject.material_slots)):
nmat = bobject.material_slots[i].material
if nmat == None:
if not bpy.data.worlds['Arm'].arm_deinterleaved_buffers:
for bobject in self.scene.objects:
if len(bobject.material_slots) > 1:
mat = bobject.material_slots[0].material
if mat == None:
continue
if vs != nmat.vertex_structure:
log.warn('Object ' + bobject.name + ' - unable to bind materials to vertex data, please separate object by material for now (select object - edit mode - P - By Material)')
break
vs = mat.vertex_structure
for i in range(len(bobject.material_slots)):
nmat = bobject.material_slots[i].material
if nmat == None:
continue
if vs != nmat.vertex_structure:
log.warn('Object ' + bobject.name + ' - unable to bind materials to vertex data, please separate object by material (select object - edit mode - P - By Material) or enable Deinterleaved Buffers in Armory Player')
break
self.output['particle_datas'] = []
self.export_particle_systems()

View file

@ -153,6 +153,16 @@ def on_scene_update_post(context):
else:
obj.active_material.is_cached = False
if hasattr(bpy.context, 'window') and bpy.context.window != None:
# Invalidate logic node tree cache if it is being edited..
areas = bpy.context.window.screen.areas
for area in areas:
if area.type == 'NODE_EDITOR':
for space in area.spaces:
if space.type == 'NODE_EDITOR':
if space.node_tree != None and space.node_tree.bl_idname == 'ArmLogicTreeType': # and space.node_tree.is_updated:
space.node_tree.is_cached = False
def recache(edit_obj):
if edit_obj.type == 'MESH':
edit_obj.data.mesh_cached = False

View file

@ -11,7 +11,6 @@ def write_data(res, defs, json_data, base_name):
shader_id += s
sres['name'] = shader_id
sres['vertex_structure'] = []
sres['contexts'] = []
# Parse
@ -21,6 +20,7 @@ def write_data(res, defs, json_data, base_name):
con['name'] = c['name']
con['constants'] = []
con['texture_units'] = []
con['vertex_structure'] = []
# Names
vert_name = c['vertex_shader'].split('.')[0]
@ -78,7 +78,7 @@ def write_data(res, defs, json_data, base_name):
with open(c['fragment_shader']) as f:
frag = f.read().splitlines()
parse_shader(sres, c, con, defs, vert, len(sres['contexts']) == 1) # Parse attribs for the first vertex shader
parse_shader(sres, c, con, defs, vert, True) # Parse attribs for vertex shader
parse_shader(sres, c, con, defs, frag, False)
if 'geometry_shader' in c:
@ -158,7 +158,7 @@ def parse_shader(sres, c, con, defs, lines, parse_attributes):
s = line.split(' ')
vd['size'] = int(s[1][-1:])
vd['name'] = s[2][:-1]
sres['vertex_structure'].append(vd)
con['vertex_structure'].append(vd)
if vertex_structure_parsing == True and len(line) > 0 and line.startswith('//') == False and line.startswith('in ') == False:
vertex_structure_parsed = True

View file

@ -358,6 +358,7 @@ def play_project(in_viewport):
khajs_path = get_khajs_path(in_viewport, state.target)
if not wrd.arm_cache_compiler or \
not os.path.isfile(khajs_path) or \
assets.khafile_defs_last != assets.khafile_defs or \
state.last_target != state.target or \
state.last_in_viewport != state.in_viewport or \
state.target == 'native':

View file

@ -31,8 +31,12 @@ def build_node_tree(node_group):
pack_path = arm.utils.safestr(bpy.data.worlds['Arm'].arm_project_package)
path = 'Sources/' + pack_path.replace('.', '/') + '/node/'
group_name = arm.utils.safesrc(node_group.name)
file = path + group_name + '.hx'
with open(path + group_name + '.hx', 'w') as f:
if node_group.is_cached and os.path.isfile(file):
return
with open(file, 'w') as f:
f.write('package ' + pack_path + '.node;\n\n')
f.write('import armory.logicnode.*;\n\n')
f.write('@:keep class ' + group_name + ' extends armory.logicnode.LogicTree {\n\n')
@ -42,6 +46,7 @@ def build_node_tree(node_group):
build_node(node, f)
f.write('\t}\n')
f.write('}\n')
node_group.is_cached = True
def build_node(node, f):
global parsed_nodes

View file

@ -92,6 +92,7 @@ def build_node_tree(world):
wrd.world_defs += '_Probes'
if cam.rp_shadowmap == 'None':
wrd.world_defs += '_NoShadows'
assets.add_khafile_def('arm_no_shadows')
if cam.rp_voxelgi:
voxelgi = True

View file

@ -19,16 +19,17 @@ import arm.material.cycles_state as c_state
basecol_texname = ''
def parse(nodes, vert, frag, geom, tesc, tese, parse_surface=True, parse_opacity=True, parse_displacement=True, basecol_only=False):
def parse(nodes, con, vert, frag, geom, tesc, tese, parse_surface=True, parse_opacity=True, parse_displacement=True, basecol_only=False):
output_node = node_by_type(nodes, 'OUTPUT_MATERIAL')
if output_node != None:
parse_output(output_node, vert, frag, geom, tesc, tese, parse_surface, parse_opacity, parse_displacement, basecol_only)
parse_output(output_node, con, vert, frag, geom, tesc, tese, parse_surface, parse_opacity, parse_displacement, basecol_only)
def parse_output(node, _vert, _frag, _geom, _tesc, _tese, _parse_surface, _parse_opacity, _parse_displacement, _basecol_only):
def parse_output(node, _con, _vert, _frag, _geom, _tesc, _tese, _parse_surface, _parse_opacity, _parse_displacement, _basecol_only):
global parsed # Compute nodes only once
global parents
global normal_written # Normal socket is linked on shader node - overwrite fs normal
global curshader # Active shader - frag for surface / tese for displacement
global con
global vert
global frag
global geom
@ -40,6 +41,7 @@ def parse_output(node, _vert, _frag, _geom, _tesc, _tese, _parse_surface, _parse
global parse_teximage_vector
global basecol_only
global basecol_texname
con = _con
vert = _vert
frag = _frag
geom = _geom
@ -417,7 +419,7 @@ def parse_rgb(node, socket):
elif node.type == 'ATTRIBUTE':
# Vcols only for now
# node.attribute_name
c_state.mat_add_elem('col', 3)
con.add_elem('col', 3)
return 'vcolor'
elif node.type == 'RGB':
@ -686,7 +688,7 @@ def texture_store(node, tex, tex_name, to_linear=False):
global parsing_basecol
global basecol_texname
c_state.mat_bind_texture(tex)
c_state.mat_add_elem('tex', 2)
con.add_elem('tex', 2)
curshader.add_uniform('sampler2D {0}'.format(tex_name))
if node.inputs[0].is_linked and parse_teximage_vector:
uv_name = parse_vector_input(node.inputs[0])
@ -713,7 +715,7 @@ def parse_vector(node, socket):
elif node.type == 'ATTRIBUTE':
# UVMaps only for now
c_state.mat_add_elem('tex', 2)
con.add_elem('tex', 2)
mat = c_state.mat_get_material()
mat_users = c_state.mat_get_material_users()
if mat_users != None and mat in mat_users:
@ -722,7 +724,7 @@ def parse_vector(node, socket):
lays = mat_user.data.uv_layers
# Second uvmap referenced
if len(lays) > 1 and node.attribute_name == lays[1].name:
c_state.mat_add_elem('tex1', 2)
con.add_elem('tex1', 2)
return 'texCoord1', 2
return 'texCoord', 2
@ -769,7 +771,7 @@ def parse_vector(node, socket):
elif socket == node.outputs[1]: # Normal
return 'vec2(0.0)', 2
elif socket == node.outputs[2]: # UV
c_state.mat_add_elem('tex', 2)
con.add_elem('tex', 2)
return 'texCoord', 2
elif socket == node.outputs[3]: # Object
return 'vec2(0.0)', 2
@ -868,7 +870,7 @@ def parse_normal_map_color_input(inp, str_inp=None):
frag.write('vec3 n = ({0}) * 2.0 - 1.0;'.format(parse_vector_input(inp)))
# frag.write('n = normalize(TBN * normalize(n));')
frag.write('n = TBN * normalize(n);')
c_state.mat_add_elem('tang', 3)
con.add_elem('tang', 3)
parse_teximage_vector = True
frag.write_pre = False

View file

@ -39,9 +39,6 @@ def mat_name():
def mat_batch():
return mat_state.batch
def mat_add_elem(name, size):
mat_state.data.add_elem(name, size)
def mat_bind_texture(tex):
mat_state.bind_textures.append(tex)

View file

@ -54,7 +54,7 @@ def make(context_id):
frag.write('float roughness;')
frag.write('float metallic;')
frag.write('float occlusion;')
cycles.parse(mat_state.nodes, vert, frag, geom, tesc, tese, parse_opacity=False)
cycles.parse(mat_state.nodes, con_decal, vert, frag, geom, tesc, tese, parse_opacity=False)
frag.write('n /= (abs(n.x) + abs(n.y) + abs(n.z));')
frag.write('n.xy = n.z >= 0.0 ? n.xy : octahedronWrap(n.xy);')

View file

@ -130,11 +130,11 @@ def make_base(con_mesh, parse_opacity):
frag.write('float occlusion;')
if parse_opacity:
frag.write('float opacity;')
cycles.parse(mat_state.nodes, vert, frag, geom, tesc, tese, parse_opacity=parse_opacity)
cycles.parse(mat_state.nodes, con_mesh, vert, frag, geom, tesc, tese, parse_opacity=parse_opacity)
if write_material_attribs_post != None:
write_material_attribs_post(frag)
if mat_state.data.is_elem('tex'):
if con_mesh.is_elem('tex'):
vert.add_out('vec2 texCoord')
vert.write('texCoord = tex;')
if tese != None:
@ -143,7 +143,7 @@ def make_base(con_mesh, parse_opacity):
make_tess.interpolate(tese, 'texCoord', 2, declare_out=frag.contains('texCoord'))
tese.write_pre = False
if mat_state.data.is_elem('tex1'):
if con_mesh.is_elem('tex1'):
vert.add_out('vec2 texCoord1')
vert.write('texCoord1 = tex1;')
if tese != None:
@ -151,7 +151,7 @@ def make_base(con_mesh, parse_opacity):
make_tess.interpolate(tese, 'texCoord1', 2, declare_out=frag.contains('texCoord1'))
tese.write_pre = False
if mat_state.data.is_elem('col'):
if con_mesh.is_elem('col'):
vert.add_out('vec3 vcolor')
vert.write('vcolor = col;')
if tese != None:
@ -159,11 +159,11 @@ def make_base(con_mesh, parse_opacity):
make_tess.interpolate(tese, 'vcolor', 3, declare_out=frag.contains('vcolor'))
tese.write_pre = False
if mat_state.data.is_elem('tang'):
if con_mesh.is_elem('tang'):
if tese != None:
vert.add_out('vec3 wnormal')
vert.add_out('vec3 wtangent')
write_norpos(vert)
write_norpos(con_mesh, vert)
vert.write('wtangent = normalize(N * tang);')
tese.add_out('mat3 TBN')
make_tess.interpolate(tese, 'wtangent', 3, normalize=True)
@ -171,13 +171,13 @@ def make_base(con_mesh, parse_opacity):
tese.write('TBN = mat3(wtangent, wbitangent, wnormal);')
else:
vert.add_out('mat3 TBN')
write_norpos(vert, declare=True)
write_norpos(con_mesh, vert, declare=True)
vert.write('vec3 tangent = normalize(N * tang);')
vert.write('vec3 bitangent = normalize(cross(wnormal, tangent));')
vert.write('TBN = mat3(tangent, bitangent, wnormal);')
else:
vert.add_out('vec3 wnormal')
write_norpos(vert)
write_norpos(con_mesh, vert)
frag.write_pre = True
frag.write_main_header('vec3 n = normalize(wnormal);')
frag.write_pre = False
@ -188,17 +188,17 @@ def make_base(con_mesh, parse_opacity):
tese.write('wposition += wnormal * disp * 0.2;')
tese.write('gl_Position = VP * vec4(wposition, 1.0);')
def write_norpos(vert, declare=False):
def write_norpos(con_mesh, vert, declare=False):
prep = ''
if declare:
prep = 'vec3 '
vert.write_pre = True
if mat_state.data.is_elem('bone'):
if con_mesh.is_elem('bone'):
make_skin.skin_pos(vert)
vert.write(prep + 'wnormal = normalize(N * (nor + 2.0 * cross(skinA.xyz, cross(skinA.xyz, nor) + skinA.w * nor)));')
else:
vert.write(prep + 'wnormal = normalize(N * nor);')
if mat_state.data.is_elem('off'):
if con_mesh.is_elem('off'):
vert.write('spos.xyz += off;')
vert.write_pre = False
@ -269,13 +269,13 @@ def make_deferred_plus(con_mesh):
vert.add_out('vec2 texCoord')
mat_state.data.add_elem('tex', 2) #### Add using cycles.py
if mat_state.data.is_elem('tex'):
if con_mesh.is_elem('tex'):
vert.write('texCoord = tex;')
else:
vert.write('texCoord = vec2(0.0);')
vert.add_out('vec3 wnormal')
write_norpos(vert)
write_norpos(con_mesh, vert)
frag.write_pre = True
frag.write_main_header('vec3 n = normalize(wnormal);')
frag.write_pre = False
@ -307,18 +307,18 @@ def make_forward_restricted(con_mesh):
frag.add_include('../../Shaders/compiled.glsl')
frag.write('vec3 basecol;')
cycles.parse(mat_state.nodes, vert, frag, geom, tesc, tese, basecol_only=True, parse_opacity=False, parse_displacement=False)
cycles.parse(mat_state.nodes, con_mesh, vert, frag, geom, tesc, tese, basecol_only=True, parse_opacity=False, parse_displacement=False)
if mat_state.data.is_elem('tex'):
if con_mesh.is_elem('tex'):
vert.add_out('vec2 texCoord')
vert.write('texCoord = tex;')
if mat_state.data.is_elem('col'):
if con_mesh.is_elem('col'):
vert.add_out('vec3 vcolor')
vert.write('vcolor = col;')
vert.add_out('vec3 wnormal')
write_norpos(vert)
write_norpos(con_mesh, vert)
frag.write_pre = True
frag.write_main_header('vec3 n = normalize(wnormal);')
frag.write_pre = False

View file

@ -98,7 +98,7 @@ def make_rect(con_rect):
frag.write('float occlusion;')
mat_state.texture_grad = True
cycles.parse(mat_state.nodes, vert, frag, None, None, None, parse_opacity=False, parse_displacement=False)
cycles.parse(mat_state.nodes, con_rect, vert, frag, None, None, None, parse_opacity=False, parse_displacement=False)
mat_state.texture_grad = False
frag.write('vec3 albedo = surfaceAlbedo(basecol, metallic);')

View file

@ -24,8 +24,6 @@ def build(material, mat_users, mat_armusers, rid):
mat_state.material = material
mat_state.nodes = material.node_tree.nodes
mat_state.data = ShaderData(material)
mat_state.data.add_elem('pos', 3)
mat_state.data.add_elem('nor', 3)
mat_state.output_node = cycles.node_by_type(mat_state.nodes, 'OUTPUT_MATERIAL')
if mat_state.output_node == None:
# Place empty material output to keep compiler happy..
@ -39,15 +37,17 @@ def build(material, mat_users, mat_armusers, rid):
if not os.path.exists(full_path):
os.makedirs(full_path)
global_elems = []
if mat_users != None:
for bo in mat_users[material]:
# GPU Skinning
if arm.utils.export_bone_data(bo):
mat_state.data.add_elem('bone', 4)
mat_state.data.add_elem('weight', 4)
global_elems.append({'name': 'bone', 'size': 4})
global_elems.append({'name': 'weight', 'size': 4})
# Instancing
if bo.instanced_children or len(bo.particle_systems) > 0:
mat_state.data.add_elem('off', 3)
global_elems.append({'name': 'off', 'size': 3})
mat_state.data.global_elems = global_elems
bind_constants = dict()
bind_textures = dict()
@ -90,7 +90,7 @@ def build(material, mat_users, mat_armusers, rid):
elif rpass_hook != None:
con = rpass_hook(rp)
write_shaders(rel_path, con, rp)
arm.utils.write_arm(full_path + '/' + matname + '_data.arm', mat_state.data.get())

View file

@ -1,3 +1,4 @@
import bpy
import arm.material.cycles as cycles
import arm.material.mat_state as mat_state
import arm.material.mat_utils as mat_utils
@ -7,7 +8,19 @@ import arm.material.make_mesh as make_mesh
import arm.utils
def make(context_id, rpasses):
con_shadowmap = mat_state.data.add_context({ 'name': context_id, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise', 'color_write_red': False, 'color_write_green': False, 'color_write_blue': False, 'color_write_alpha': False })
is_disp = mat_utils.disp_linked(mat_state.output_node) and mat_state.material.height_tess_shadows
vs = [{'name': 'pos', 'size': 3}]
if is_disp:
vs.append({'name': 'nor', 'size': 3})
# TODO: interleaved buffer has to match vertex structure of mesh context
if not bpy.data.worlds['Arm'].arm_deinterleaved_buffers:
vs.append({'name': 'nor', 'size': 3})
# vs.append({'name': 'tex', 'size': 2})
con_shadowmap = mat_state.data.add_context({ 'name': context_id, 'vertex_structure': vs, 'depth_write': True, 'compare_mode': 'less', 'cull_mode': 'clockwise', 'color_write_red': False, 'color_write_green': False, 'color_write_blue': False, 'color_write_alpha': False })
vert = con_shadowmap.make_vert()
frag = con_shadowmap.make_frag()
@ -23,7 +36,7 @@ def make(context_id, rpasses):
# TODO: pass vbuf with proper struct
if gapi.startswith('direct3d'):
vert.write('vec3 t1 = nor; // TODO: Temp for d3d')
if mat_state.data.is_elem('tex'):
if con_shadowmap.is_elem('tex'):
vert.write('vec2 t2 = tex; // TODO: Temp for d3d')
parse_opacity = 'translucent' in rpasses
@ -32,13 +45,13 @@ def make(context_id, rpasses):
frag.write('float dotNV;')
frag.write('float opacity;')
if mat_state.data.is_elem('bone'):
if con_shadowmap.is_elem('bone'):
make_skin.skin_pos(vert)
if mat_state.data.is_elem('off'):
if con_shadowmap.is_elem('off'):
vert.write('spos.xyz += off;')
if mat_utils.disp_linked(mat_state.output_node) and mat_state.material.height_tess_shadows:
if is_disp:
tesc = con_shadowmap.make_tesc()
tese = con_shadowmap.make_tese()
tesc.ins = vert.outs
@ -62,23 +75,23 @@ def make(context_id, rpasses):
make_tess.interpolate(tese, 'wposition', 3)
make_tess.interpolate(tese, 'wnormal', 3, normalize=True)
cycles.parse(mat_state.nodes, vert, frag, geom, tesc, tese, parse_surface=False, parse_opacity=parse_opacity)
cycles.parse(mat_state.nodes, con_shadowmap, vert, frag, geom, tesc, tese, parse_surface=False, parse_opacity=parse_opacity)
if mat_state.data.is_elem('tex'):
if con_shadowmap.is_elem('tex'):
vert.add_out('vec2 texCoord')
vert.write('texCoord = tex;')
tese.write_pre = True
make_tess.interpolate(tese, 'texCoord', 2, declare_out=frag.contains('texCoord'))
tese.write_pre = False
if mat_state.data.is_elem('tex1'):
if con_shadowmap.is_elem('tex1'):
vert.add_out('vec2 texCoord1')
vert.write('texCoord1 = tex1;')
tese.write_pre = True
make_tess.interpolate(tese, 'texCoord1', 2, declare_out=frag.contains('texCoord1'))
tese.write_pre = False
if mat_state.data.is_elem('col'):
if con_shadowmap.is_elem('col'):
vert.add_out('vec3 vcolor')
vert.write('vcolor = col;')
tese.write_pre = True
@ -95,17 +108,17 @@ def make(context_id, rpasses):
vert.write('gl_Position = LWVP * spos;')
if parse_opacity:
cycles.parse(mat_state.nodes, vert, frag, geom, tesc, tese, parse_surface=False, parse_opacity=True)
cycles.parse(mat_state.nodes, con_shadowmap, vert, frag, geom, tesc, tese, parse_surface=False, parse_opacity=True)
if mat_state.data.is_elem('tex'):
if con_shadowmap.is_elem('tex'):
vert.add_out('vec2 texCoord')
vert.write('texCoord = tex;')
if mat_state.data.is_elem('tex1'):
if con_shadowmap.is_elem('tex1'):
vert.add_out('vec2 texCoord1')
vert.write('texCoord1 = tex1;')
if mat_state.data.is_elem('col'):
if con_shadowmap.is_elem('col'):
vert.add_out('vec3 vcolor')
vert.write('vcolor = col;')

View file

@ -29,7 +29,7 @@ def make(context_id):
vert.add_include('../../Shaders/compiled.glsl')
if mat_state.data.is_elem('tex'):
if con_voxel.is_elem('tex'):
vert.add_out('vec2 texCoordGeom')
vert.write('texCoordGeom = tex;')
@ -46,7 +46,7 @@ def make(context_id):
geom.add_out('vec3 wnormal')
if is_shadows:
geom.add_out('vec4 lampPos')
if mat_state.data.is_elem('tex'):
if con_voxel.is_elem('tex'):
geom.add_out('vec2 texCoord')
geom.write('const vec3 p1 = wpositionGeom[1] - wpositionGeom[0];')
@ -57,7 +57,7 @@ def make(context_id):
geom.write(' wnormal = wnormalGeom[i];')
if is_shadows:
geom.write(' lampPos = lampPosGeom[i];')
if mat_state.data.is_elem('tex'):
if con_voxel.is_elem('tex'):
geom.write(' texCoord = texCoordGeom[i];')
geom.write(' if (p.z > p.x && p.z > p.y) {')
geom.write(' gl_Position = vec4(wposition.x, wposition.y, 0.0, 1.0);')
@ -110,7 +110,7 @@ def make(context_id):
frag.write_pre = False
frag.write('float dotNV = 0.0;')
frag.write('float dotNL = max(dot(wnormal, l), 0.0);')
cycles.parse(mat_state.nodes, vert, frag, geom, tesc, tese, parse_opacity=False, parse_displacement=False)
cycles.parse(mat_state.nodes, con_voxel, vert, frag, geom, tesc, tese, parse_opacity=False, parse_displacement=False)
frag.write('vec3 color;')
frag.write('if (lightShadow > 0) color = basecol * visibility * lightColor * dotNL * attenuate(distance(wposition * voxelgiDimensions.x, lightPos));')
frag.write('else color = (basecol - 1.0);') # Emission only when no lamp or shadowmap is present

View file

@ -24,7 +24,7 @@ def make(context_id):
vert.add_include('../../Shaders/compiled.glsl')
if mat_state.data.is_elem('tex'):
if con_voxel.is_elem('tex'):
vert.add_out('vec2 texCoordGeom')
vert.write('texCoordGeom = tex;')
@ -35,7 +35,7 @@ def make(context_id):
geom.add_out('vec3 wposition')
geom.add_out('vec3 wnormal')
if mat_state.data.is_elem('tex'):
if con_voxel.is_elem('tex'):
geom.add_out('vec2 texCoord')
geom.write('const vec3 p1 = wpositionGeom[1] - wpositionGeom[0];')
@ -44,7 +44,7 @@ def make(context_id):
geom.write('for (uint i = 0; i < 3; ++i) {')
geom.write(' wposition = wpositionGeom[i];')
geom.write(' wnormal = wnormalGeom[i];')
if mat_state.data.is_elem('tex'):
if con_voxel.is_elem('tex'):
geom.write(' texCoord = texCoordGeom[i];')
geom.write(' if (p.z > p.x && p.z > p.y) {')
geom.write(' gl_Position = vec4(wposition.x, wposition.y, 0.0, 1.0);')
@ -82,7 +82,7 @@ def make(context_id):
frag.write_pre = False
frag.write('float dotNV = 0.0;')
# frag.write('float dotNL = max(dot(wnormal, l), 0.0);')
cycles.parse(mat_state.nodes, vert, frag, geom, tesc, tese, parse_opacity=False, parse_displacement=False)
cycles.parse(mat_state.nodes, con_voxel, vert, frag, geom, tesc, tese, parse_opacity=False, parse_displacement=False)
# frag.write('vec3 color = texture(voxels, voxel).rgb / 2.0 + indirectDiffuseLight(wnormal, wposition / voxelgiDimensions.x).rgb * basecol;')

View file

@ -88,7 +88,7 @@ class Shader:
out_ext = ''
if self.shader_type == 'vert' and self.vertex_structure_as_vsinput: # Vertex structure as vertex shader input
vs = self.context.shader_data['vertex_structure']
vs = self.context.data['vertex_structure']
for e in vs:
self.add_in('vec' + str(e['size']) + ' ' + e['name'])

View file

@ -6,47 +6,23 @@ class ShaderData:
def __init__(self, material):
self.material = material
self.contexts = []
self.global_elems = [] # bone, weight, off
self.sd = {}
self.data = {}
self.data['shader_datas'] = [self.sd]
self.matname = arm.utils.safesrc(material.name)
self.sd['name'] = self.matname + '_data'
self.sd['vertex_structure'] = []
self.sd['contexts'] = []
def add_elem(self, name, size):
elem = { 'name': name, 'size': size }
if elem not in self.sd['vertex_structure']:
self.sd['vertex_structure'].append(elem)
def is_elem(self, name):
for elem in self.sd['vertex_structure']:
if elem['name'] == name:
return True
return False
def get_elem(self, name):
for elem in self.sd['vertex_structure']:
if elem['name'] == name:
return elem
return None
def add_context(self, props):
con = ShaderContext(self.material, self.sd, props)
if con not in self.sd['contexts']:
for elem in self.global_elems:
con.add_elem(elem['name'], elem['size'])
self.sd['contexts'].append(con.get())
return con
def get(self):
# TODO: temporary, Sort vertex data
for sd in self.data['shader_datas']:
vs = []
ar = ['pos', 'nor', 'tex', 'tex1', 'col', 'tang', 'bone', 'weight', 'off']
for ename in ar:
elem = self.get_elem(ename)
if elem != None:
vs.append(elem)
sd['vertex_structure'] = vs
return self.data
class ShaderContext:
@ -65,6 +41,10 @@ class ShaderContext:
self.data['depth_write'] = props['depth_write']
self.data['compare_mode'] = props['compare_mode']
self.data['cull_mode'] = props['cull_mode']
if 'vertex_structure' in props:
self.data['vertex_structure'] = props['vertex_structure']
else:
self.data['vertex_structure'] = [{'name': 'pos', 'size': 3}, {'name': 'nor', 'size': 3}]
if 'blend_source' in props:
self.data['blend_source'] = props['blend_source']
if 'blend_destination' in props:
@ -91,6 +71,34 @@ class ShaderContext:
self.data['constants'] = []
self.constants = self.data['constants']
def add_elem(self, name, size):
elem = { 'name': name, 'size': size }
if elem not in self.data['vertex_structure']:
self.data['vertex_structure'].append(elem)
self.sort_vs()
def sort_vs(self):
# TODO: sort vertex data
vs = []
ar = ['pos', 'nor', 'tex', 'tex1', 'col', 'tang', 'bone', 'weight', 'off']
for ename in ar:
elem = self.get_elem(ename)
if elem != None:
vs.append(elem)
self.data['vertex_structure'] = vs
def is_elem(self, name):
for elem in self.data['vertex_structure']:
if elem['name'] == name:
return True
return False
def get_elem(self, name):
for elem in self.data['vertex_structure']:
if elem['name'] == name:
return elem
return None
def get(self):
return self.data

View file

@ -493,6 +493,7 @@ def init_properties():
bpy.types.World.generate_voxelgi_dimensions = bpy.props.FloatVectorProperty(name="Dimensions", description="Voxelization bounds", size=3, default=[16, 16, 16], update=assets.invalidate_shader_cache)
# For material
bpy.types.NodeSocket.is_uniform = bpy.props.BoolProperty(name="Is Uniform", description="Mark node sockets to be processed as material uniforms", default=False)
bpy.types.NodeTree.is_cached = bpy.props.BoolProperty(name="Node Tree Cached", description="No need to reexport node tree", default=False)
# bpy.types.Node.is_uniform = bpy.props.BoolProperty(name="Is Uniform", description="Mark node values to be processed as material uniforms", default=False)
bpy.types.Material.signature = bpy.props.StringProperty(name="Signature", description="Unique string generated from material nodes", default="")
bpy.types.Material.is_cached = bpy.props.BoolProperty(name="Material Cached", description="No need to reexport material data", default=False, update=update_mat_cache)

View file

@ -42,9 +42,6 @@ let project = new Project('""" + arm.utils.safestr(wrd.arm_project_name) + """')
project.addSources('Sources');
""")
# TODO: Move to khamake
f.write("project.addDefine('arm_" + arm.utils.get_gapi() + "');\n")
# TODO: Khamake bug workaround - assets & shaders located in folder starting with '.' get discarded - copy them to project
check_dot_path = False
if '/.' in sdk_path:
@ -74,7 +71,7 @@ project.addSources('Sources');
f.write('project.addLibrary("{0}");\n'.format(lib.name))
if export_physics:
f.write("project.addDefine('arm_physics');\n")
assets.add_khafile_def('arm_physics')
f.write(add_armory_library(sdk_path + '/lib/', 'haxebullet'))
if state.target == 'krom' or state.target == 'html5':
ammojs_path = sdk_path + '/lib/haxebullet/js/ammo/ammo.js'
@ -82,7 +79,7 @@ project.addSources('Sources');
f.write(add_assets(ammojs_path))
if export_navigation:
f.write("project.addDefine('arm_navigation');\n")
assets.add_khafile_def('arm_navigation')
f.write(add_armory_library(sdk_path + '/lib/', 'haxerecast'))
if state.target == 'krom' or state.target == 'html5':
recastjs_path = sdk_path + '/lib/haxerecast/js/recast/recast.js'
@ -94,7 +91,7 @@ project.addSources('Sources');
if wrd.arm_cache_compiler and (is_play or (state.target == 'html5' and not is_publish)):
# Load shaders manually
f.write("project.addDefine('arm_debug');\n")
assets.add_khafile_def('arm_debug')
for ref in shader_references:
f.write("project.addShaders('" + ref + "');\n")
@ -108,7 +105,7 @@ project.addSources('Sources');
f.write(add_assets(ref))
if wrd.arm_play_console:
f.write("project.addDefine('arm_profile');\n")
assets.add_khafile_def('arm_profile')
if wrd.arm_play_console or wrd.arm_ui:
f.write(add_armory_library(sdk_path, 'lib/zui'))
@ -119,19 +116,19 @@ project.addSources('Sources');
f.write(add_armory_library(sdk_path, 'lib/hscript'))
if wrd.arm_minimize == False:
f.write("project.addDefine('arm_json');\n")
assets.add_khafile_def('arm_json')
if wrd.arm_deinterleaved_buffers == True:
f.write("project.addDefine('arm_deinterleaved');\n")
assets.add_khafile_def('arm_deinterleaved')
if wrd.arm_batch_meshes == True:
f.write("project.addDefine('arm_batch');\n")
assets.add_khafile_def('arm_batch')
if wrd.arm_stream_scene:
f.write("project.addDefine('arm_stream');\n")
assets.add_khafile_def('arm_stream')
if wrd.generate_gpu_skin == False:
f.write("project.addDefine('arm_cpu_skin');\n")
assets.add_khafile_def('arm_cpu_skin')
for d in assets.khafile_defs:
f.write("project.addDefine('" + d + "');\n")