def create_world_shaders(world: bpy.types.World): """Creates fragment and vertex shaders for the given world.""" global shader_datas world_name = arm.utils.safestr(world.name) pass_name = 'World_' + world_name shader_props = { 'name': world_name, 'depth_write': False, 'compare_mode': 'less', 'cull_mode': 'clockwise', 'color_attachments': ['_HDR'], 'vertex_elements': [{'name': 'pos', 'data': 'float3'}, {'name': 'nor', 'data': 'float3'}] } shader_data = {'name': world_name + '_data', 'contexts': [shader_props]} # ShaderContext expects a material, but using a world also works shader_context = ShaderContext(world, shader_data, shader_props) vert = shader_context.make_vert(custom_name="World_" + world_name) frag = shader_context.make_frag(custom_name="World_" + world_name) # Update name, make_vert() and make_frag() above need another name # to work shader_context.data['name'] = pass_name vert.add_out('vec3 normal') vert.add_uniform('mat4 SMVP', link="_skydomeMatrix") frag.add_include('compiled.inc') frag.add_in('vec3 normal') frag.add_out('vec4 fragColor') frag.write_attrib('vec3 n = normalize(normal);') vert.write('''normal = nor; vec4 position = SMVP * vec4(pos, 1.0); gl_Position = vec4(position);''') build_node_tree(world, frag, vert, shader_context) # TODO: Rework shader export so that it doesn't depend on materials # to prevent workaround code like this rel_path = os.path.join(arm.utils.build_dir(), 'compiled', 'Shaders') full_path = os.path.join(arm.utils.get_fp(), rel_path) if not os.path.exists(full_path): os.makedirs(full_path) # Output: World_[world_name].[frag/vert].glsl make_shader.write_shader(rel_path, shader_context.vert, 'vert', world_name, 'World') make_shader.write_shader(rel_path, shader_context.frag, 'frag', world_name, 'World') # Write shader data file shader_data_file = pass_name + '_data.arm' arm.utils.write_arm(os.path.join(full_path, shader_data_file), {'contexts': [shader_context.data]}) shader_data_path = os.path.join(arm.utils.get_fp_build(), 'compiled', 'Shaders', shader_data_file) assets.add_shader_data(shader_data_path) assets.add_shader_pass(pass_name) assets.shader_passes_assets[pass_name] = shader_context.data shader_datas.append({'contexts': [shader_context.data], 'name': pass_name})
def build(material, mat_users, mat_armusers): mat_state.mat_users = mat_users mat_state.mat_armusers = mat_armusers mat_state.material = material mat_state.nodes = material.node_tree.nodes mat_state.data = ShaderData(material) 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.. mat_state.output_node = mat_state.nodes.new('ShaderNodeOutputMaterial') wrd = bpy.data.worlds['Arm'] rpdat = arm.utils.get_rp() rpasses = mat_utils.get_rpasses(material) matname = arm.utils.safesrc(arm.utils.asset_name(material)) rel_path = arm.utils.build_dir() + '/compiled/Shaders/' full_path = arm.utils.get_fp() + '/' + rel_path if not os.path.exists(full_path): os.makedirs(full_path) global_elems = [] if mat_users != None and material in mat_users: for bo in mat_users[material]: # GPU Skinning if arm.utils.export_bone_data(bo): global_elems.append({'name': 'bone', 'size': 4}) global_elems.append({'name': 'weight', 'size': 4}) # Instancing if bo.arm_instanced or material.arm_particle_flag: global_elems.append({'name': 'off', 'size': 3}) mat_state.data.global_elems = global_elems bind_constants = dict() bind_textures = dict() for rp in rpasses: car = [] bind_constants[rp] = car mat_state.bind_constants = car tar = [] bind_textures[rp] = tar mat_state.bind_textures = tar con = None if rpdat.rp_driver != 'Armory' and arm.api.drivers[rpdat.rp_driver]['make_rpass'] != None: con = arm.api.drivers[rpdat.rp_driver]['make_rpass'](rp) if con != None: pass elif rp == 'mesh': con = make_mesh.make(rp) elif rp == 'rect': con = make_rect.make(rp) elif rp == 'shadowmap': con = make_depth.make(rp, rpasses, shadowmap=True) elif rp == 'translucent': con = make_transluc.make(rp) elif rp == 'overlay': con = make_overlay.make(rp) elif rp == 'decal': con = make_decal.make(rp) elif rp == 'depth': con = make_depth.make(rp, rpasses) elif rp == 'voxel': con = make_voxel.make(rp) elif rpass_hook != None: con = rpass_hook(rp) write_shaders(rel_path, con, rp, matname) arm.utils.write_arm(full_path + '/' + matname + '_data.arm', mat_state.data.get()) shader_data_name = matname + '_data' shader_data_path = arm.utils.get_fp_build() + '/compiled/Shaders/' + shader_data_name + '.arm' assets.add_shader_data(shader_data_path) return rpasses, mat_state.data, shader_data_name, bind_constants, bind_textures
def build(material: Material, mat_users: Dict[Material, List[Object]], mat_armusers) -> Tuple: mat_state.mat_users = mat_users mat_state.mat_armusers = mat_armusers mat_state.material = material mat_state.nodes = material.node_tree.nodes mat_state.data = ShaderData(material) mat_state.output_node = cycles.node_by_type(mat_state.nodes, 'OUTPUT_MATERIAL') if mat_state.output_node is None: # Place empty material output to keep compiler happy.. mat_state.output_node = mat_state.nodes.new('ShaderNodeOutputMaterial') wrd = bpy.data.worlds['Arm'] rpdat = arm.utils.get_rp() rpasses = mat_utils.get_rpasses(material) is_emissive = mat_utils.is_emmisive(material) if is_emissive and '_Emission' not in wrd.world_defs: wrd.world_defs += '_Emission' matname = arm.utils.safesrc(arm.utils.asset_name(material)) rel_path = arm.utils.build_dir() + '/compiled/Shaders/' full_path = arm.utils.get_fp() + '/' + rel_path if not os.path.exists(full_path): os.makedirs(full_path) make_instancing_and_skinning(material, mat_users) bind_constants = dict() bind_textures = dict() for rp in rpasses: car = [] bind_constants[rp] = car mat_state.bind_constants = car tar = [] bind_textures[rp] = tar mat_state.bind_textures = tar con = None if rpdat.rp_driver != 'Armory' and arm.api.drivers[ rpdat.rp_driver]['make_rpass'] is not None: con = arm.api.drivers[rpdat.rp_driver]['make_rpass'](rp) if con is not None: pass elif rp == 'mesh': con = make_mesh.make(rp, rpasses) elif rp == 'shadowmap': con = make_depth.make(rp, rpasses, shadowmap=True) elif rp == 'translucent': con = make_transluc.make(rp) elif rp == 'overlay': con = make_overlay.make(rp) elif rp == 'decal': con = make_decal.make(rp) elif rp == 'depth': con = make_depth.make(rp, rpasses) elif rp == 'voxel': con = make_voxel.make(rp) elif rpass_hook is not None: con = rpass_hook(rp) write_shaders(rel_path, con, rp, matname) shader_data_name = matname + '_data' if wrd.arm_single_data_file: if 'shader_datas' not in arm.exporter.current_output: arm.exporter.current_output['shader_datas'] = [] arm.exporter.current_output['shader_datas'].append( mat_state.data.get()['shader_datas'][0]) else: arm.utils.write_arm(full_path + '/' + matname + '_data.arm', mat_state.data.get()) shader_data_path = arm.utils.get_fp_build( ) + '/compiled/Shaders/' + shader_data_name + '.arm' assets.add_shader_data(shader_data_path) return rpasses, mat_state.data, shader_data_name, bind_constants, bind_textures