def build_node_trees(assets_path): s = bpy.data.filepath.split(os.path.sep) s.pop() fp = os.path.sep.join(s) os.chdir(fp) # Make sure Assets dir exists if not os.path.exists('build/compiled/Assets/renderpaths'): os.makedirs('build/compiled/Assets/renderpaths') build_node_trees.assets_path = assets_path # Always include assets.add(assets_path + 'brdf.png') assets.add_embedded_data('brdf.png') bpy.data.worlds['Arm'].rp_defs = '' # Export render path for each camera parsed_paths = [] for cam in bpy.data.cameras: # if cam.game_export if cam.renderpath_path not in parsed_paths: node_group = bpy.data.node_groups[cam.renderpath_path] build_node_tree(cam, node_group) parsed_paths.append(cam.renderpath_path)
def make_ssao_pass(stages, node_group, node): sc = 0.5 if bpy.data.worlds['Arm'].generate_ssao_half_res else 1.0 make_quad_pass(stages, node_group, node, target_index=1, bind_target_indices=[3, 4], bind_target_constants=['gbufferD', 'gbuffer0'], shader_context='ssao_pass/ssao_pass/ssao_pass', viewport_scale=sc) make_quad_pass( stages, node_group, node, target_index=2, bind_target_indices=[1, 4], bind_target_constants=['tex', 'gbuffer0'], shader_context='blur_edge_pass/blur_edge_pass/blur_edge_pass_x', viewport_scale=sc) make_quad_pass( stages, node_group, node, target_index=1, bind_target_indices=[2, 4], bind_target_constants=['tex', 'gbuffer0'], shader_context='blur_edge_pass/blur_edge_pass/blur_edge_pass_y') assets.add(build_node_trees.assets_path + 'noise8.png') assets.add_embedded_data('noise8.png')
def make_ssao_reproject_pass(stages, node_group, node): make_quad_pass( stages, node_group, node, target_index=1, bind_target_indices=[3, 4, 2, 5], bind_target_constants=['gbufferD', 'gbuffer0', 'slast', 'sveloc'], shader_context= 'ssao_reproject_pass/ssao_reproject_pass/ssao_reproject_pass') make_quad_pass( stages, node_group, node, target_index=2, bind_target_indices=[1, 4], bind_target_constants=['tex', 'gbuffer0'], shader_context='blur_edge_pass/blur_edge_pass/blur_edge_pass_x') make_quad_pass( stages, node_group, node, target_index=1, bind_target_indices=[2, 4], bind_target_constants=['tex', 'gbuffer0'], shader_context='blur_edge_pass/blur_edge_pass/blur_edge_pass_y') assets.add(build_node_trees.assets_path + 'noise8.png') assets.add_embedded_data('noise8.png')
def make_apply_ssao_pass(stages, node_group, node): make_quad_pass(stages, node_group, node, target_index=2, bind_target_indices=[4, 5], bind_target_constants=['gbufferD', 'gbuffer0'], shader_context='ssao_pass/ssao_pass/ssao_pass') make_quad_pass( stages, node_group, node, target_index=3, bind_target_indices=[2, 5], bind_target_constants=['tex', 'gbuffer0'], shader_context='blur_edge_pass/blur_edge_pass/blur_edge_pass_x') make_quad_pass( stages, node_group, node, target_index=1, bind_target_indices=[3, 5], bind_target_constants=['tex', 'gbuffer0'], shader_context='blur_edge_pass/blur_edge_pass/blur_edge_pass_y_blend') assets.add(build_node_trees.assets_path + 'noise8.png') assets.add_embedded_data('noise8.png')
def make_draw_world(stage, node_group, node, dome=True): if dome: stage['command'] = 'draw_skydome' else: stage['command'] = 'draw_material_quad' # stage['params'].append(wname + '_material/' + wname + '_material/world') stage['params'].append('_worldMaterial') # Link to active world # Link assets if '_EnvClouds' in bpy.data.worlds['Arm'].world_defs: assets.add(build_node_trees.assets_path + 'noise256.png') assets.add_embedded_data('noise256.png')
def make_smaa_pass(stages, node_group, node): stage = {} stage['params'] = [] make_set_target(stage, node_group, node, target_index=2) stages.append(stage) stage = {} stage['params'] = [] make_clear_target(stage, color_val=[0.0, 0.0, 0.0, 0.0]) stages.append(stage) make_quad_pass( stages, node_group, node, target_index=None, bind_target_indices=[4], bind_target_constants=['colorTex'], shader_context='smaa_edge_detect/smaa_edge_detect/smaa_edge_detect') stage = {} stage['params'] = [] make_set_target(stage, node_group, node, target_index=3) stages.append(stage) stage = {} stage['params'] = [] make_clear_target(stage, color_val=[0.0, 0.0, 0.0, 0.0]) stages.append(stage) make_quad_pass( stages, node_group, node, target_index=None, bind_target_indices=[2], bind_target_constants=['edgesTex'], shader_context='smaa_blend_weight/smaa_blend_weight/smaa_blend_weight') make_quad_pass( stages, node_group, node, target_index=1, bind_target_indices=[4, 3, 5], bind_target_constants=['colorTex', 'blendTex', 'sveloc'], shader_context= 'smaa_neighborhood_blend/smaa_neighborhood_blend/smaa_neighborhood_blend' ) assets.add(build_node_trees.assets_path + 'smaa_area.png') assets.add(build_node_trees.assets_path + 'smaa_search.png') assets.add_embedded_data('smaa_area.png') assets.add_embedded_data('smaa_search.png')
def make_draw_compositor(stage, node_group, node, with_fxaa=False): scon = 'compositor_pass' wrd = bpy.data.worlds['Arm'] world_defs = wrd.world_defs + wrd.rp_defs compositor_defs = make_compositor.parse_defs( bpy.data.scenes[0].node_tree) # Thrown in scene 0 for now compositor_defs += '_CTone' + wrd.generate_tonemap # Additional compositor flags compo_depth = False # Read depth # compo_pos = False # Construct position from depth if with_fxaa: # FXAA directly in compositor, useful for forward path compositor_defs += '_CFXAA' if wrd.generate_letterbox: compositor_defs += '_CLetterbox' if wrd.generate_grain: compositor_defs += '_CGrain' if bpy.data.scenes[0].cycles.film_exposure != 1.0: compositor_defs += '_CExposure' if wrd.generate_fog: compositor_defs += '_CFog' # compo_pos = True if build_node_tree.cam.dof_distance > 0.0: compositor_defs += '_CDOF' compo_depth = True # if compo_pos: # compositor_defs += '_CPos' # compo_depth = True if compo_depth: compositor_defs += '_CDepth' if wrd.generate_lens_texture != '': compositor_defs += '_CLensTex' assets.add_embedded_data('lenstexture.jpg') if wrd.generate_fisheye: compositor_defs += '_CFishEye' if wrd.generate_vignette: compositor_defs += '_CVignette' wrd.compo_defs = compositor_defs defs = world_defs + compositor_defs data_name = scon + defs stage['command'] = 'draw_shader_quad' stage['params'].append(data_name + '/' + data_name + '/' + scon) # Include data and shaders assets.add_shader2(scon, data_name)
def make_rpath(): assets_path = arm.utils.get_sdk_path() + 'armory/Assets/' wrd = bpy.data.worlds['Arm'] rpdat = arm.utils.get_rp() if rpdat.rp_hdr: assets.add_khafile_def('rp_hdr') else: wrd.world_defs += '_LDR' if rpdat.rp_shadows: wrd.world_defs += '_ShadowMap' assets.add_khafile_def('rp_shadowmap') assets.add_khafile_def('rp_shadowmap_cascade={0}'.format(rpdat.rp_shadowmap_cascade)) assets.add_khafile_def('rp_shadowmap_cube={0}'.format(rpdat.rp_shadowmap_cube)) assets.add_khafile_def('rp_background={0}'.format(rpdat.rp_background)) if rpdat.rp_background == 'World': assets.add_shader_pass('world_pass') if '_EnvClouds' in wrd.world_defs: assets.add(assets_path + 'noise256.png') assets.add_embedded_data('noise256.png') if rpdat.rp_render_to_texture: assets.add_khafile_def('rp_render_to_texture') if rpdat.rp_compositornodes: assets.add_khafile_def('rp_compositornodes') compo_depth = False if rpdat.arm_tonemap != 'Off': wrd.compo_defs = '_CTone' + rpdat.arm_tonemap if rpdat.rp_antialiasing == 'FXAA': wrd.compo_defs += '_CFXAA' if rpdat.arm_letterbox: wrd.compo_defs += '_CLetterbox' if rpdat.arm_grain: wrd.compo_defs += '_CGrain' if bpy.data.scenes[0].cycles.film_exposure != 1.0: wrd.compo_defs += '_CExposure' if rpdat.arm_fog: wrd.compo_defs += '_CFog' compo_depth = True if len(bpy.data.cameras) > 0 and bpy.data.cameras[0].dof_distance > 0.0: wrd.compo_defs += '_CDOF' compo_depth = True if compo_depth: wrd.compo_defs += '_CDepth' assets.add_khafile_def('rp_compositordepth') if rpdat.arm_lens_texture != '': wrd.compo_defs += '_CLensTex' assets.add_embedded_data('lenstexture.jpg') if rpdat.arm_fisheye: wrd.compo_defs += '_CFishEye' if rpdat.arm_vignette: wrd.compo_defs += '_CVignette' if rpdat.arm_lensflare: wrd.compo_defs += '_CGlare' if rpdat.arm_lut_texture != '': wrd.compo_defs += '_CLUT' assets.add_embedded_data('luttexture.jpg') if '_CDOF' in wrd.compo_defs or '_CFXAA' in wrd.compo_defs or '_CSharpen' in wrd.compo_defs: wrd.compo_defs += '_CTexStep' if '_CDOF' in wrd.compo_defs or '_CFog' in wrd.compo_defs or '_CGlare' in wrd.compo_defs: wrd.compo_defs += '_CCameraProj' assets.add_shader_pass('compositor_pass') else: assets.add_shader_pass('copy_pass') assets.add_khafile_def('rp_antialiasing={0}'.format(rpdat.rp_antialiasing)) if rpdat.rp_antialiasing == 'SMAA' or rpdat.rp_antialiasing == 'TAA': assets.add_shader_pass('smaa_edge_detect') assets.add_shader_pass('smaa_blend_weight') assets.add_shader_pass('smaa_neighborhood_blend') assets.add(assets_path + 'smaa_area.png') assets.add(assets_path + 'smaa_search.png') assets.add_embedded_data('smaa_area.png') assets.add_embedded_data('smaa_search.png') wrd.world_defs += '_SMAA' if rpdat.rp_antialiasing == 'TAA': assets.add_shader_pass('taa_pass') assets.add_shader_pass('copy_pass') if rpdat.rp_antialiasing == 'TAA' or rpdat.rp_motionblur == 'Object': assets.add_khafile_def('arm_veloc') wrd.world_defs += '_Veloc' if rpdat.rp_antialiasing == 'TAA': assets.add_khafile_def('arm_taa') assets.add_khafile_def('rp_supersampling={0}'.format(rpdat.rp_supersampling)) if rpdat.rp_supersampling == '4': assets.add_shader_pass('supersample_resolve') if rpdat.rp_volumetriclight: wrd.world_defs += '_Sun' assets.add_khafile_def('rp_volumetriclight') assets.add_shader_pass('volumetric_light') assets.add_shader_pass('blur_bilat_pass') assets.add_shader_pass('blur_bilat_blend_pass') assets.add(assets_path + 'blue_noise64.png') assets.add_embedded_data('blue_noise64.png') if rpdat.rp_bloom: assets.add_khafile_def('rp_bloom') assets.add_shader_pass('bloom_pass') assets.add_shader_pass('blur_gaus_pass') if rpdat.arm_rp_resolution == 'Custom': assets.add_khafile_def('rp_resolution_filter={0}'.format(rpdat.arm_rp_resolution_filter))
def build_node_tree(world): output = {} dat = {} output['material_datas'] = [dat] wname = arm.utils.safestr(world.name) dat['name'] = wname + '_material' context = {} dat['contexts'] = [context] context['name'] = 'world' context['bind_constants'] = [] context['bind_textures'] = [] bpy.data.worlds['Arm'].world_defs = '' # Traverse world node tree output_node = nodes.get_node_by_type(world.node_tree, 'OUTPUT_WORLD') if output_node != None: parse_world_output(world, output_node, context) # Clear to color if no texture or sky is provided wrd = bpy.data.worlds['Arm'] if '_EnvSky' not in wrd.world_defs and '_EnvTex' not in wrd.world_defs: if '_EnvImg' not in wrd.world_defs: wrd.world_defs += '_EnvCol' # Irradiance json file name world.world_envtex_name = wname world.world_envtex_irr_name = wname write_probes.write_color_irradiance(wname, world.world_envtex_color) # Clouds enabled if wrd.generate_clouds: wrd.world_defs += '_EnvClouds' # Percentage closer soft shadows if wrd.generate_pcss_state == 'On': wrd.world_defs += '_PCSS' sdk_path = arm.utils.get_sdk_path() assets.add(sdk_path + 'armory/Assets/noise64.png') assets.add_embedded_data('noise64.png') # Screen-space ray-traced shadows if wrd.generate_ssrs: wrd.world_defs += '_SSRS' if wrd.generate_two_sided_area_lamp: wrd.world_defs += '_TwoSidedAreaLamp' # Alternative models if wrd.lighting_model == 'Cycles': wrd.world_defs += '_Cycles' # TODO: Lamp texture test.. if wrd.generate_lamp_texture != '': bpy.data.worlds['Arm'].world_defs += '_LampColTex' if not wrd.generate_lamp_falloff: bpy.data.worlds['Arm'].world_defs += '_NoLampFalloff' voxelgi = False for cam in bpy.data.cameras: if cam.is_probe: 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 if cam.rp_dfrs: wrd.world_defs += '_DFRS' assets.add_khafile_def('arm_sdf') if cam.rp_dfao: wrd.world_defs += '_DFAO' assets.add_khafile_def('arm_sdf') if voxelgi: assets.add_khafile_def('arm_voxelgi') if wrd.voxelgi_revoxelize: assets.add_khafile_def('arm_voxelgi_revox') if wrd.voxelgi_multibounce: wrd.world_defs += '_VoxelGIMulti' wrd.world_defs += '_VoxelGI' wrd.world_defs += '_Rad' # Always do radiance for voxels wrd.world_defs += '_Irr' if arm.utils.get_gapi().startswith( 'direct3d'): # Flip Y axis in drawQuad command wrd.world_defs += '_InvY' # Area lamps for lamp in bpy.data.lamps: if lamp.type == 'AREA': wrd.world_defs += '_PolyLight' break # Data will be written after render path has been processed to gather all defines return output
def build(): rpdat = arm.utils.get_rp() if rpdat.rp_driver != 'Armory' and arm.api.drivers[ rpdat.rp_driver]['make_rpath'] != None: arm.api.drivers[rpdat.rp_driver]['make_rpath']() return assets_path = arm.utils.get_sdk_path() + '/armory/Assets/' wrd = bpy.data.worlds['Arm'] add_world_defs() mobile_mat = rpdat.arm_material_model == 'Mobile' or rpdat.arm_material_model == 'Solid' if not mobile_mat: # Always include assets.add(assets_path + 'brdf.png') assets.add_embedded_data('brdf.png') if rpdat.rp_hdr: assets.add_khafile_def('rp_hdr') assets.add_khafile_def('rp_renderer={0}'.format(rpdat.rp_renderer)) if rpdat.rp_depthprepass: assets.add_khafile_def('rp_depthprepass') if rpdat.rp_shadows: assets.add_khafile_def('rp_shadowmap') assets.add_khafile_def('rp_shadowmap_cascade={0}'.format( arm.utils.get_cascade_size(rpdat))) assets.add_khafile_def('rp_shadowmap_cube={0}'.format( rpdat.rp_shadowmap_cube)) assets.add_khafile_def('rp_background={0}'.format(rpdat.rp_background)) if rpdat.rp_background == 'World': assets.add_shader_pass('world_pass') if '_EnvClouds' in wrd.world_defs: assets.add(assets_path + 'clouds_base.raw') assets.add_embedded_data('clouds_base.raw') assets.add(assets_path + 'clouds_detail.raw') assets.add_embedded_data('clouds_detail.raw') assets.add(assets_path + 'clouds_map.png') assets.add_embedded_data('clouds_map.png') if rpdat.rp_renderer == 'Deferred' and not rpdat.rp_compositornodes: assets.add_shader_pass('copy_pass') if rpdat.rp_render_to_texture: assets.add_khafile_def('rp_render_to_texture') if rpdat.rp_renderer == 'Forward' and not rpdat.rp_compositornodes: assets.add_shader_pass('copy_pass') if rpdat.rp_compositornodes: assets.add_khafile_def('rp_compositornodes') compo_depth = False if rpdat.arm_tonemap != 'Off': wrd.compo_defs = '_CTone' + rpdat.arm_tonemap if rpdat.rp_antialiasing == 'FXAA': wrd.compo_defs += '_CFXAA' if rpdat.arm_letterbox: wrd.compo_defs += '_CLetterbox' if rpdat.arm_grain: wrd.compo_defs += '_CGrain' if rpdat.arm_sharpen: wrd.compo_defs += '_CSharpen' if bpy.data.scenes[0].view_settings.exposure != 0.0: wrd.compo_defs += '_CExposure' if rpdat.arm_fog: wrd.compo_defs += '_CFog' compo_depth = True focus_distance = 0.0 if len(bpy.data.cameras) > 0 and bpy.data.cameras[0].dof.use_dof: focus_distance = bpy.data.cameras[0].dof.focus_distance if focus_distance > 0.0: wrd.compo_defs += '_CDOF' compo_depth = True if rpdat.arm_lens_texture != '': wrd.compo_defs += '_CLensTex' assets.add_embedded_data('lenstexture.jpg') if rpdat.arm_lens_texture_masking: wrd.compo_defs += '_CLensTexMasking' if rpdat.arm_fisheye: wrd.compo_defs += '_CFishEye' if rpdat.arm_vignette: wrd.compo_defs += '_CVignette' if rpdat.arm_lensflare: wrd.compo_defs += '_CGlare' compo_depth = True if rpdat.arm_lut_texture != '': wrd.compo_defs += '_CLUT' assets.add_embedded_data('luttexture.jpg') if '_CDOF' in wrd.compo_defs or '_CFXAA' in wrd.compo_defs or '_CSharpen' in wrd.compo_defs: wrd.compo_defs += '_CTexStep' if '_CDOF' in wrd.compo_defs or '_CFog' in wrd.compo_defs or '_CGlare' in wrd.compo_defs: wrd.compo_defs += '_CCameraProj' if compo_depth: wrd.compo_defs += '_CDepth' assets.add_khafile_def('rp_compositordepth') if rpdat.rp_pp: wrd.compo_defs += '_CPostprocess' assets.add_shader_pass('compositor_pass') assets.add_khafile_def('rp_antialiasing={0}'.format( rpdat.rp_antialiasing)) if rpdat.rp_antialiasing == 'SMAA' or rpdat.rp_antialiasing == 'TAA': assets.add_shader_pass('smaa_edge_detect') assets.add_shader_pass('smaa_blend_weight') assets.add_shader_pass('smaa_neighborhood_blend') assets.add(assets_path + 'smaa_area.png') assets.add(assets_path + 'smaa_search.png') assets.add_embedded_data('smaa_area.png') assets.add_embedded_data('smaa_search.png') wrd.world_defs += '_SMAA' if rpdat.rp_antialiasing == 'TAA': assets.add_shader_pass('taa_pass') assets.add_shader_pass('copy_pass') if rpdat.rp_antialiasing == 'TAA' or rpdat.rp_motionblur == 'Object': assets.add_khafile_def('arm_veloc') wrd.world_defs += '_Veloc' if rpdat.rp_antialiasing == 'TAA': assets.add_khafile_def('arm_taa') assets.add_khafile_def('rp_supersampling={0}'.format( rpdat.rp_supersampling)) if rpdat.rp_supersampling == '4': assets.add_shader_pass('supersample_resolve') assets.add_khafile_def('rp_ssgi={0}'.format(rpdat.rp_ssgi)) if rpdat.rp_ssgi != 'Off': wrd.world_defs += '_SSAO' if rpdat.rp_ssgi == 'SSAO': assets.add_shader_pass('ssao_pass') assets.add_shader_pass('blur_edge_pass') else: assets.add_shader_pass('ssgi_pass') assets.add_shader_pass('blur_edge_pass') if rpdat.arm_ssgi_half_res: assets.add_khafile_def('rp_ssgi_half') if rpdat.rp_bloom: assets.add_khafile_def('rp_bloom') assets.add_shader_pass('bloom_pass') assets.add_shader_pass('blur_gaus_pass') if rpdat.rp_ssr: assets.add_khafile_def('rp_ssr') assets.add_shader_pass('ssr_pass') assets.add_shader_pass('blur_adaptive_pass') if rpdat.arm_ssr_half_res: assets.add_khafile_def('rp_ssr_half') if rpdat.rp_overlays: assets.add_khafile_def('rp_overlays') if rpdat.rp_translucency: assets.add_khafile_def('rp_translucency') assets.add_shader_pass('translucent_resolve') if rpdat.rp_stereo: assets.add_khafile_def('rp_stereo') assets.add_khafile_def('arm_vr') wrd.world_defs += '_VR' has_voxels = arm.utils.voxel_support() if rpdat.rp_voxelao and has_voxels and rpdat.arm_material_model == 'Full': assets.add_khafile_def('rp_voxelao') assets.add_khafile_def('rp_voxelgi_resolution={0}'.format( rpdat.rp_voxelgi_resolution)) assets.add_khafile_def('rp_voxelgi_resolution_z={0}'.format( rpdat.rp_voxelgi_resolution_z)) if rpdat.arm_rp_resolution == 'Custom': assets.add_khafile_def('rp_resolution_filter={0}'.format( rpdat.arm_rp_resolution_filter)) if rpdat.rp_renderer == 'Deferred': if rpdat.arm_material_model == 'Full': assets.add_shader_pass('deferred_light') else: # mobile, solid assets.add_shader_pass('deferred_light_' + rpdat.arm_material_model.lower()) assets.add_khafile_def('rp_material_' + rpdat.arm_material_model.lower()) if len(bpy.data.lightprobes) > 0: wrd.world_defs += '_Probes' assets.add_khafile_def('rp_probes') assets.add_shader_pass('probe_planar') assets.add_shader_pass('probe_cubemap') assets.add_shader_pass('copy_pass') if rpdat.rp_volumetriclight: assets.add_khafile_def('rp_volumetriclight') assets.add_shader_pass('volumetric_light') assets.add_shader_pass('blur_bilat_pass') assets.add_shader_pass('blur_bilat_blend_pass') assets.add(assets_path + 'blue_noise64.png') assets.add_embedded_data('blue_noise64.png') if rpdat.rp_decals: assets.add_khafile_def('rp_decals') if rpdat.rp_water: assets.add_khafile_def('rp_water') assets.add_shader_pass('water_pass') assets.add_shader_pass('copy_pass') assets.add(assets_path + 'water_base.png') assets.add_embedded_data('water_base.png') assets.add(assets_path + 'water_detail.png') assets.add_embedded_data('water_detail.png') assets.add(assets_path + 'water_foam.png') assets.add_embedded_data('water_foam.png') if rpdat.rp_blending: assets.add_khafile_def('rp_blending') if rpdat.rp_sss: assets.add_khafile_def('rp_sss') wrd.world_defs += '_SSS' assets.add_shader_pass('sss_pass') if (rpdat.rp_ssr and rpdat.arm_ssr_half_res) or (rpdat.rp_ssgi != 'Off' and rpdat.arm_ssgi_half_res): assets.add_shader_pass('downsample_depth') if rpdat.rp_motionblur != 'Off': assets.add_khafile_def('rp_motionblur={0}'.format(rpdat.rp_motionblur)) assets.add_shader_pass('copy_pass') if rpdat.rp_motionblur == 'Camera': assets.add_shader_pass('motion_blur_pass') else: assets.add_shader_pass('motion_blur_veloc_pass') if rpdat.rp_compositornodes and rpdat.rp_autoexposure: assets.add_khafile_def('rp_autoexposure') assets.add_shader_pass('histogram_pass') if rpdat.rp_dynres: assets.add_khafile_def('rp_dynres') if rpdat.rp_pp: assets.add_khafile_def('rp_pp') if rpdat.rp_chromatic_aberration: assets.add_shader_pass('copy_pass') assets.add_khafile_def('rp_chromatic_aberration') assets.add_shader_pass('chromatic_aberration_pass') gbuffer2 = '_Veloc' in wrd.world_defs if gbuffer2: assets.add_khafile_def('rp_gbuffer2') wrd.world_defs += '_gbuffer2' if callback != None: callback()
def add_world_defs(): wrd = bpy.data.worlds['Arm'] rpdat = arm.utils.get_rp() # Screen-space ray-traced shadows if rpdat.arm_ssrs: wrd.world_defs += '_SSRS' if rpdat.arm_micro_shadowing: wrd.world_defs += '_MicroShadowing' if rpdat.arm_two_sided_area_light: wrd.world_defs += '_TwoSidedAreaLight' # Store contexts if rpdat.rp_hdr == False: wrd.world_defs += '_LDR' if wrd.arm_light_ies_texture != '': wrd.world_defs += '_LightIES' assets.add_embedded_data('iestexture.png') if wrd.arm_light_clouds_texture != '': wrd.world_defs += '_LightClouds' assets.add_embedded_data('cloudstexture.png') if rpdat.rp_renderer == 'Deferred': assets.add_khafile_def('arm_deferred') wrd.world_defs += '_Deferred' # Shadows if rpdat.rp_shadows: wrd.world_defs += '_ShadowMap' if rpdat.rp_shadowmap_cascades != '1': wrd.world_defs += '_CSM' assets.add_khafile_def('arm_csm') # SS if rpdat.rp_ssgi == 'RTGI' or rpdat.rp_ssgi == 'RTAO': if rpdat.rp_ssgi == 'RTGI': wrd.world_defs += '_RTGI' if rpdat.arm_ssgi_rays == '9': wrd.world_defs += '_SSGICone9' if rpdat.rp_autoexposure: wrd.world_defs += '_AutoExposure' has_voxels = arm.utils.voxel_support() if rpdat.rp_voxelao and has_voxels and rpdat.arm_material_model == 'Full': wrd.world_defs += '_VoxelCones' + rpdat.arm_voxelgi_cones if rpdat.arm_voxelgi_revoxelize: assets.add_khafile_def('arm_voxelgi_revox') if rpdat.arm_voxelgi_camera: wrd.world_defs += '_VoxelGICam' if rpdat.arm_voxelgi_temporal: assets.add_khafile_def('arm_voxelgi_temporal') wrd.world_defs += '_VoxelGITemporal' wrd.world_defs += '_VoxelAOvar' # Write a shader variant if rpdat.arm_voxelgi_shadows: wrd.world_defs += '_VoxelShadow' if rpdat.arm_voxelgi_occ == 0.0: wrd.world_defs += '_VoxelAONoTrace' if arm.utils.get_legacy_shaders() or 'ios' in state.target: wrd.world_defs += '_Legacy' assets.add_khafile_def('arm_legacy') # Light defines point_lights = 0 for bo in bpy.data.objects: # TODO: temp if bo.type == 'LIGHT': light = bo.data if light.type == 'AREA' and '_LTC' not in wrd.world_defs: point_lights += 1 wrd.world_defs += '_LTC' assets.add_khafile_def('arm_ltc') if light.type == 'SUN' and '_Sun' not in wrd.world_defs: wrd.world_defs += '_Sun' if light.type == 'POINT' or light.type == 'SPOT': point_lights += 1 if light.type == 'SPOT' and '_Spot' not in wrd.world_defs: wrd.world_defs += '_Spot' assets.add_khafile_def('arm_spot') if point_lights == 1: wrd.world_defs += '_SinglePoint' elif point_lights > 1: wrd.world_defs += '_Clusters' assets.add_khafile_def('arm_clusters') if '_Rad' in wrd.world_defs and '_Brdf' not in wrd.world_defs: wrd.world_defs += '_Brdf'
def build_node_tree(world): output = {} dat = {} output['material_datas'] = [dat] wname = arm.utils.safestr(world.name) dat['name'] = wname + '_material' context = {} dat['contexts'] = [context] context['name'] = 'world' context['bind_constants'] = [] context['bind_textures'] = [] wrd = bpy.data.worlds['Arm'] wrd.world_defs = '' rpdat = arm.utils.get_rp() # Traverse world node tree parsed = False if world.node_tree != None: output_node = nodes.get_node_by_type(world.node_tree, 'OUTPUT_WORLD') if output_node != None: parse_world_output(world, output_node, context) parsed = True if parsed == False: if wrd.arm_irradiance and rpdat.arm_material_model != 'Restricted': wrd.world_defs += '_Irr' envmap_strength_const = {} envmap_strength_const['name'] = 'envmapStrength' envmap_strength_const['float'] = 1.0 context['bind_constants'].append(envmap_strength_const) world.arm_envtex_color = [0.051, 0.051, 0.051, 1.0] world.arm_envtex_strength = envmap_strength_const['float'] # Clear to color if no texture or sky is provided if '_EnvSky' not in wrd.world_defs and '_EnvTex' not in wrd.world_defs: if '_EnvImg' not in wrd.world_defs: wrd.world_defs += '_EnvCol' # Irradiance json file name world.arm_envtex_name = wname world.arm_envtex_irr_name = wname write_probes.write_color_irradiance(wname, world.arm_envtex_color) # Clouds enabled if rpdat.arm_clouds: wrd.world_defs += '_EnvClouds' # Percentage closer soft shadows if rpdat.arm_pcss_state == 'On': wrd.world_defs += '_PCSS' sdk_path = arm.utils.get_sdk_path() assets.add(sdk_path + 'armory/Assets/noise64.png') assets.add_embedded_data('noise64.png') # Screen-space ray-traced shadows if rpdat.arm_ssrs: wrd.world_defs += '_SSRS' if wrd.arm_two_sided_area_lamp: wrd.world_defs += '_TwoSidedAreaLamp' # Store contexts if rpdat.rp_hdr == False: wrd.world_defs += '_LDR' # Alternative models if rpdat.arm_material_model == 'Cycles': wrd.world_defs += '_Cycles' # TODO: Lamp texture test.. if wrd.arm_lamp_texture != '': wrd.world_defs += '_LampColTex' if wrd.arm_lamp_ies_texture != '': wrd.world_defs += '_LampIES' assets.add_embedded_data('iestexture.png') voxelgi = False voxelao = False if rpdat.rp_shadowmap == 'None': wrd.world_defs += '_NoShadows' assets.add_khafile_def('arm_no_shadows') if rpdat.rp_voxelgi: voxelgi = True elif rpdat.rp_voxelao: voxelao = True if rpdat.rp_dfrs: wrd.world_defs += '_DFRS' assets.add_khafile_def('arm_sdf') if rpdat.rp_dfao: wrd.world_defs += '_DFAO' assets.add_khafile_def('arm_sdf') if rpdat.rp_dfgi: wrd.world_defs += '_DFGI' assets.add_khafile_def('arm_sdf') wrd.world_defs += '_Rad' # Always do radiance for gi wrd.world_defs += '_Irr' if voxelgi: assets.add_khafile_def('arm_voxelgi') if rpdat.arm_voxelgi_revoxelize: assets.add_khafile_def('arm_voxelgi_revox') if rpdat.arm_voxelgi_camera: wrd.world_defs += '_VoxelGICam' if rpdat.arm_voxelgi_shadows: wrd.world_defs += '_VoxelGIDirect' wrd.world_defs += '_VoxelGIShadow' if rpdat.arm_voxelgi_refraction: wrd.world_defs += '_VoxelGIDirect' wrd.world_defs += '_VoxelGIRefract' wrd.world_defs += '_VoxelGI' wrd.world_defs += '_Rad' # Always do radiance for voxels wrd.world_defs += '_Irr' elif voxelao: assets.add_khafile_def('arm_voxelgi') if rpdat.arm_voxelgi_revoxelize: assets.add_khafile_def('arm_voxelgi_revox') wrd.world_defs += '_VoxelAO' wrd.world_defs += '_Rad' wrd.world_defs += '_Irr' if arm.utils.get_gapi().startswith( 'direct3d'): # Flip Y axis in drawQuad command wrd.world_defs += '_InvY' # Area lamps for lamp in bpy.data.lamps: if lamp.type == 'AREA': wrd.world_defs += '_PolyLight' break # Data will be written after render path has been processed to gather all defines return output
def add_world_defs(): wrd = bpy.data.worlds['Arm'] rpdat = arm.utils.get_rp() # Screen-space ray-traced shadows if rpdat.arm_ssrs: wrd.world_defs += '_SSRS' if rpdat.arm_two_sided_area_light: wrd.world_defs += '_TwoSidedAreaLight' # Store contexts if rpdat.rp_hdr == False: wrd.world_defs += '_LDR' if wrd.arm_light_ies_texture != '': wrd.world_defs += '_LightIES' assets.add_embedded_data('iestexture.png') if wrd.arm_light_clouds_texture != '': wrd.world_defs += '_LightClouds' assets.add_embedded_data('cloudstexture.png') if rpdat.rp_renderer == 'Deferred': assets.add_khafile_def('arm_deferred') wrd.world_defs += '_Deferred' # GI voxelgi = False voxelao = False has_voxels = arm.utils.voxel_support() if has_voxels and rpdat.arm_material_model == 'Full': if rpdat.rp_gi == 'Voxel GI': voxelgi = True elif rpdat.rp_gi == 'Voxel AO': voxelao = True # Shadows if rpdat.rp_shadows: wrd.world_defs += '_ShadowMap' if rpdat.rp_shadowmap_cascades != '1': if voxelgi: log.warn('Disabling shadow cascades - Voxel GI does not support cascades yet') else: wrd.world_defs += '_CSM' assets.add_khafile_def('arm_csm') # SS if rpdat.rp_ssgi == 'RTGI' or rpdat.rp_ssgi == 'RTAO': if rpdat.rp_ssgi == 'RTGI': wrd.world_defs += '_RTGI' if rpdat.arm_ssgi_rays == '9': wrd.world_defs += '_SSGICone9' if rpdat.rp_autoexposure: wrd.world_defs += '_AutoExposure' if voxelgi or voxelao: assets.add_khafile_def('arm_voxelgi') wrd.world_defs += '_VoxelCones' + rpdat.arm_voxelgi_cones if rpdat.arm_voxelgi_revoxelize: assets.add_khafile_def('arm_voxelgi_revox') if rpdat.arm_voxelgi_camera: wrd.world_defs += '_VoxelGICam' if rpdat.arm_voxelgi_temporal: assets.add_khafile_def('arm_voxelgi_temporal') wrd.world_defs += '_VoxelGITemporal' if voxelgi: wrd.world_defs += '_VoxelGI' # assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_light/voxel_light.comp.glsl') # if rpdat.arm_voxelgi_bounces != "1": # assets.add_khafile_def('rp_gi_bounces={0}'.format(rpdat.arm_voxelgi_bounces)) # assets.add_shader_external(arm.utils.get_sdk_path() + '/armory/Shaders/voxel_bounce/voxel_bounce.comp.glsl') # if rpdat.arm_voxelgi_shadows: # wrd.world_defs += '_VoxelGIShadow' if rpdat.rp_voxelgi_relight: assets.add_khafile_def('rp_voxelgi_relight') elif voxelao: wrd.world_defs += '_VoxelAOvar' # Write a shader variant if arm.utils.get_legacy_shaders() and not state.is_viewport: wrd.world_defs += '_Legacy' # Light defines point_lights = 0 for bo in bpy.data.objects: # TODO: temp if bo.type == 'LIGHT': light = bo.data if light.type == 'AREA' and '_LTC' not in wrd.world_defs: wrd.world_defs += '_LTC' assets.add_khafile_def('arm_ltc') if light.type == 'SUN' and '_Sun' not in wrd.world_defs: wrd.world_defs += '_Sun' if light.type == 'POINT' or light.type == 'SPOT': point_lights += 1 if light.type == 'SPOT' and '_Spot' not in wrd.world_defs: wrd.world_defs += '_Spot' assets.add_khafile_def('arm_spot') if point_lights == 1: wrd.world_defs += '_SinglePoint' elif point_lights > 1: wrd.world_defs += '_Clusters' assets.add_khafile_def('arm_clusters') if '_Rad' in wrd.world_defs or '_VoxelGI' in wrd.world_defs: wrd.world_defs += '_Brdf'
def parse_value(node, socket): if node.type == 'GROUP': if node.node_tree.name.startswith('Armory PBR'): # Displacement if socket == node.outputs[1]: res = parse_value_input(node.inputs[10]) if node.inputs[ 11].is_linked or node.inputs[11].default_value != 1.0: res = "({0} * {1})".format( res, parse_value_input(node.inputs[11])) return res else: return None else: return parse_group(node, socket) elif node.type == 'GROUP_INPUT': return parse_group_input(node, socket) elif node.type == 'ATTRIBUTE': # Pass time till drivers are implemented if node.attribute_name == 'time': curshader.add_uniform('float time', link='_time') return 'time' else: return '0.0' elif node.type == 'CAMERA': # View Z Depth if socket == node.outputs[1]: return 'gl_FragCoord.z' # View Distance else: return 'length(eyeDir)' elif node.type == 'FRESNEL': 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) elif node.type == 'NEW_GEOMETRY': if socket == node.outputs[6]: # Backfacing return '0.0' elif socket == node.outputs[7]: # Pointiness return '0.0' elif node.type == 'HAIR_INFO': # Is Strand # Intercept # Thickness return '0.5' elif node.type == 'LAYER_WEIGHT': blend = parse_value_input(node.inputs[0]) # nor = parse_vector_input(node.inputs[1]) if socket == node.outputs[0]: # Fresnel return 'clamp(pow(1.0 - dotNV, (1.0 - {0}) * 10.0), 0.0, 1.0)'.format( blend) elif socket == node.outputs[1]: # Facing return '((1.0 - dotNV) * {0})'.format(blend) elif node.type == 'LIGHT_PATH': if socket == node.outputs[0]: # Is Camera Ray return '1.0' elif socket == node.outputs[1]: # Is Shadow Ray return '0.0' elif socket == node.outputs[2]: # Is Diffuse Ray return '1.0' elif socket == node.outputs[3]: # Is Glossy Ray return '1.0' elif socket == node.outputs[4]: # Is Singular Ray return '0.0' elif socket == node.outputs[5]: # Is Reflection Ray return '0.0' elif socket == node.outputs[6]: # Is Transmission Ray return '0.0' elif socket == node.outputs[7]: # Ray Length return '0.0' elif socket == node.outputs[8]: # Ray Depth return '0.0' elif socket == node.outputs[9]: # Transparent Depth return '0.0' elif socket == node.outputs[10]: # Transmission Depth return '0.0' elif node.type == 'OBJECT_INFO': 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' elif node.type == 'PARTICLE_INFO': if socket == node.outputs[0]: # Index return '0.0' elif socket == node.outputs[1]: # Age return '0.0' elif socket == node.outputs[2]: # Lifetime return '0.0' elif socket == node.outputs[4]: # Size return '0.0' elif node.type == 'VALUE': return tovec1(node.outputs[0].default_value) elif node.type == 'WIREFRAME': #node.use_pixel_size # size = parse_value_input(node.inputs[0]) return '0.0' elif node.type == 'TEX_BRICK': return '0.0' elif node.type == 'TEX_CHECKER': # TODO: do not recompute when color socket is also connected curshader.add_function(functions.str_tex_checker) if node.inputs[0].is_linked: co = parse_vector_input(node.inputs[0]) else: co = 'wposition' col1 = parse_vector_input(node.inputs[1]) col2 = parse_vector_input(node.inputs[2]) scale = parse_value_input(node.inputs[3]) return 'tex_checker({0}, {1}, {2}, {3}).r'.format( co, col1, col2, scale) elif node.type == 'TEX_GRADIENT': return '0.0' elif node.type == 'TEX_IMAGE': # Already fetched if res_var_name(node, node.outputs[0]) in parsed: return '{0}.a'.format(store_var_name(node)) tex_name = arm.utils.safe_source_name(node.name) tex = texture.make_texture(node, tex_name) if tex != None: return '{0}.a'.format(texture_store(node, tex, tex_name)) else: 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) elif node.type == 'TEX_MAGIC': return '0.0' elif node.type == 'TEX_MUSGRAVE': # Fall back to noise curshader.add_function(functions.str_tex_noise) if node.inputs[0].is_linked: co = parse_vector_input(node.inputs[0]) else: co = 'wposition' scale = parse_value_input(node.inputs[1]) # detail = parse_value_input(node.inputs[2]) # distortion = parse_value_input(node.inputs[3]) return 'tex_noise_f({0} * {1})'.format(co, scale) elif node.type == 'TEX_NOISE': curshader.add_function(functions.str_tex_noise) if node.inputs[0].is_linked: co = parse_vector_input(node.inputs[0]) else: co = 'wposition' scale = parse_value_input(node.inputs[1]) # detail = parse_value_input(node.inputs[2]) # distortion = parse_value_input(node.inputs[3]) return 'tex_noise({0} * {1})'.format(co, scale) elif node.type == 'TEX_POINTDENSITY': return '0.0' elif node.type == 'TEX_VORONOI': curshader.add_function(functions.str_tex_voronoi) assets.add(arm.utils.get_sdk_path() + '/armory/Assets/' + 'noise64.png') assets.add_embedded_data('noise64.png') curshader.add_uniform('sampler2D snoise', link='_noise64') if node.inputs[0].is_linked: co = parse_vector_input(node.inputs[0]) else: co = 'wposition' scale = parse_value_input(node.inputs[1]) if node.coloring == 'INTENSITY': return 'tex_voronoi({0} * {1}).a'.format(co, scale) else: # CELLS return 'tex_voronoi({0} * {1}).r'.format(co, scale) elif node.type == 'TEX_WAVE': return '0.0' elif node.type == 'LIGHT_FALLOFF': # Constant, linear, quadratic # Shaders default to quadratic for now return '1.0' elif node.type == 'NORMAL': nor = parse_vector_input(node.inputs[0]) return 'dot({0}, {1})'.format(tovec3(node.outputs[0].default_value), nor) elif node.type == 'VALTORGB': # ColorRamp return '1.0' elif node.type == 'MATH': 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': out_val = 'sin({0})'.format(val1) elif op == 'COSINE': out_val = 'cos({0})'.format(val1) elif op == 'TANGENT': out_val = 'tan({0})'.format(val1) elif op == 'ARCSINE': out_val = 'asin({0})'.format(val1) elif op == 'ARCCOSINE': out_val = 'acos({0})'.format(val1) elif op == 'ARCTANGENT': out_val = 'atan({0})'.format(val1) 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': # out_val = 'round({0})'.format(val1) out_val = 'floor({0} + 0.5)'.format(val1) 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': # out_val = 'float({0} % {1})'.format(val1, val2) out_val = 'mod({0}, {1})'.format(val1, val2) 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 elif node.type == 'RGBTOBW': 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) elif node.type == 'SEPHSV': return '0.0' elif node.type == 'SEPRGB': 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) elif node.type == 'SEPXYZ': 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) elif node.type == 'VECT_MATH': 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'
def parse_rgb(node, socket): if node.type == 'GROUP': return parse_group(node, socket) elif node.type == 'GROUP_INPUT': return parse_group_input(node, socket) elif node.type == 'ATTRIBUTE': # Vcols only for now # node.attribute_name mat_state.data.add_elem('col', 3) return 'vcolor' elif node.type == 'RGB': return tovec3(socket.default_value) elif node.type == 'TEX_BRICK': # Pass through return tovec3([0.0, 0.0, 0.0]) elif node.type == 'TEX_CHECKER': curshader.add_function(functions.str_tex_checker) if node.inputs[0].is_linked: co = parse_vector_input(node.inputs[0]) else: co = 'wposition' col1 = parse_vector_input(node.inputs[1]) col2 = parse_vector_input(node.inputs[2]) scale = parse_value_input(node.inputs[3]) return 'tex_checker({0}, {1}, {2}, {3})'.format(co, col1, col2, scale) elif node.type == 'TEX_ENVIRONMENT': # Pass through return tovec3([0.0, 0.0, 0.0]) elif node.type == 'TEX_GRADIENT': if node.inputs[0].is_linked: co = parse_vector_input(node.inputs[0]) else: co = 'wposition' 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 'vec3(clamp({0}, 0.0, 1.0))'.format(f) elif node.type == 'TEX_IMAGE': # Already fetched if res_var_name(node, node.outputs[1]) in parsed: return '{0}.rgb'.format(store_var_name(node)) tex_name = arm.utils.safe_source_name(node.name) tex = texture.make_texture(node, tex_name) if tex != None: to_linear = parsing_basecol and not tex['file'].endswith('.hdr') return '{0}.rgb'.format( texture_store(node, tex, tex_name, to_linear)) elif node.image == None: # Empty texture tex = {} tex['name'] = tex_name tex['file'] = '' return '{0}.rgb'.format(texture_store(node, tex, tex_name, True)) else: 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) elif node.type == 'TEX_MAGIC': # Pass through return tovec3([0.0, 0.0, 0.0]) elif node.type == 'TEX_MUSGRAVE': # Fall back to noise curshader.add_function(functions.str_tex_noise) if node.inputs[0].is_linked: co = parse_vector_input(node.inputs[0]) else: co = 'wposition' scale = parse_value_input(node.inputs[1]) # detail = parse_value_input(node.inputs[2]) # distortion = parse_value_input(node.inputs[3]) return 'vec3(tex_noise_f({0} * {1}))'.format(co, scale) elif node.type == 'TEX_NOISE': curshader.add_function(functions.str_tex_noise) if node.inputs[0].is_linked: co = parse_vector_input(node.inputs[0]) else: co = 'wposition' scale = parse_value_input(node.inputs[1]) # detail = parse_value_input(node.inputs[2]) # distortion = parse_value_input(node.inputs[3]) # Slow.. return 'vec3(tex_noise({0} * {1}), tex_noise({0} * {1} + 0.33), tex_noise({0} * {1} + 0.66))'.format( co, scale) elif node.type == 'TEX_POINTDENSITY': # Pass through return tovec3([0.0, 0.0, 0.0]) elif node.type == 'TEX_SKY': # Pass through return tovec3([0.0, 0.0, 0.0]) elif node.type == 'TEX_VORONOI': curshader.add_function(functions.str_tex_voronoi) assets.add(arm.utils.get_sdk_path() + '/armory/Assets/' + 'noise64.png') assets.add_embedded_data('noise64.png') curshader.add_uniform('sampler2D snoise', link='_noise64') if node.inputs[0].is_linked: co = parse_vector_input(node.inputs[0]) else: co = 'wposition' scale = parse_value_input(node.inputs[1]) if node.coloring == 'INTENSITY': return 'vec3(tex_voronoi({0} / {1}).a)'.format(co, scale) else: # CELLS return 'tex_voronoi({0} / {1}).rgb'.format(co, scale) elif node.type == 'TEX_WAVE': # Pass through return tovec3([0.0, 0.0, 0.0]) elif node.type == 'BRIGHTCONTRAST': out_col = parse_vector_input(node.inputs[0]) bright = parse_value_input(node.inputs[1]) contr = parse_value_input(node.inputs[2]) curshader.add_function(\ """vec3 brightcontrast(const vec3 col, const float bright, const float contr) { float a = 1.0 + contr; float b = bright - contr * 0.5; return max(a * col + b, 0.0); } """) return 'brightcontrast({0}, {1}, {2})'.format(out_col, bright, contr) elif node.type == 'GAMMA': out_col = parse_vector_input(node.inputs[0]) gamma = parse_value_input(node.inputs[1]) return 'pow({0}, vec3({1}))'.format(out_col, gamma) elif node.type == 'HUE_SAT': curshader.add_function(functions.str_hsv_to_rgb) 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) elif node.type == 'INVERT': 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) elif node.type == 'MIX_RGB': fac = parse_value_input(node.inputs[0]) fac_var = node_name(node.name) + '_fac' curshader.write('float {0} = {1};'.format(fac_var, fac)) col1 = parse_vector_input(node.inputs[1]) col2 = parse_vector_input(node.inputs[2]) blend = node.blend_type if blend == 'MIX': out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) elif blend == 'ADD': out_col = 'mix({0}, {0} + {1}, {2})'.format(col1, col2, fac_var) elif blend == 'MULTIPLY': out_col = 'mix({0}, {0} * {1}, {2})'.format(col1, col2, fac_var) elif blend == 'SUBTRACT': out_col = 'mix({0}, {0} - {1}, {2})'.format(col1, col2, fac_var) elif blend == 'SCREEN': out_col = '(vec3(1.0) - (vec3(1.0 - {2}) + {2} * (vec3(1.0) - {1})) * (vec3(1.0) - {0}))'.format( col1, col2, fac_var) elif blend == 'DIVIDE': out_col = '(vec3((1.0 - {2}) * {0} + {2} * {0} / {1}))'.format( col1, col2, fac_var) elif blend == 'DIFFERENCE': out_col = 'mix({0}, abs({0} - {1}), {2})'.format( col1, col2, fac_var) elif blend == 'DARKEN': out_col = 'min({0}, {1} * {2})'.format(col1, col2, fac_var) elif blend == 'LIGHTEN': out_col = 'max({0}, {1} * {2})'.format(col1, col2, fac_var) elif blend == 'OVERLAY': out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix elif blend == 'DODGE': out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix elif blend == 'BURN': out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix elif blend == 'HUE': out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix elif blend == 'SATURATION': out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix elif blend == 'VALUE': out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix elif blend == 'COLOR': out_col = 'mix({0}, {1}, {2})'.format(col1, col2, fac_var) # Revert to mix 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': 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) if node.use_clamp: return 'clamp({0}, vec3(0.0), vec3(1.0))'.format(out_col) else: return out_col elif node.type == 'CURVE_RGB': # Pass throuh return parse_vector_input(node.inputs[1]) elif node.type == 'BLACKBODY': # Pass constant return tovec3([0.84, 0.38, 0.0]) elif node.type == 'VALTORGB': # ColorRamp fac = parse_value_input(node.inputs[0]) interp = node.color_ramp.interpolation elems = node.color_ramp.elements if len(elems) == 1: return tovec3(elems[0].color) if interp == 'CONSTANT': fac_var = node_name(node.name) + '_fac' curshader.write('float {0} = {1};'.format(fac_var, fac)) # Get index out_i = '0' for i in range(1, len(elems)): out_i += ' + ({0} > {1} ? 1 : 0)'.format( fac_var, elems[i].position) # Write cols array cols_var = node_name(node.name) + '_cols' curshader.write('vec3 {0}[{1}];'.format(cols_var, len(elems))) for i in range(0, len(elems)): curshader.write('{0}[{1}] = vec3({2}, {3}, {4});'.format( cols_var, i, elems[i].color[0], elems[i].color[1], elems[i].color[2])) 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); return 'mix({0}, {1}, clamp(({2} - {3}) * (1.0 / (1.0 - {3})), 0.0, 1.0))'.format( tovec3(elems[0].color), tovec3(elems[1].color), fac, elems[0].position) elif node.type == 'COMBHSV': # vec3 hsv2rgb(vec3 c) { # vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); # vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); # return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); # } # vec3 rgb2hsv(vec3 c) { # vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); # vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); # vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); # float d = q.x - min(q.w, q.y); # float e = 1.0e-10; # return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); # } # Pass constant return tovec3([0.0, 0.0, 0.0]) elif node.type == 'COMBRGB': 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) elif node.type == 'WAVELENGTH': # Pass constant return tovec3([0.0, 0.27, 0.19])
def build_node_tree(world): output = {} dat = {} output['material_datas'] = [dat] wname = arm.utils.safestr(world.name) dat['name'] = wname + '_material' context = {} dat['contexts'] = [context] context['name'] = 'world' context['bind_constants'] = [] context['bind_textures'] = [] wrd = bpy.data.worlds['Arm'] wrd.world_defs = '' rpdat = arm.utils.get_rp() # Traverse world node tree parsed = False if world.node_tree != None: output_node = node_utils.get_node_by_type(world.node_tree, 'OUTPUT_WORLD') if output_node != None: parse_world_output(world, output_node, context) parsed = True if parsed == False: solid_mat = rpdat.arm_material_model == 'Solid' if wrd.arm_irradiance and not solid_mat: wrd.world_defs += '_Irr' envmap_strength_const = {} envmap_strength_const['name'] = 'envmapStrength' envmap_strength_const['float'] = 1.0 context['bind_constants'].append(envmap_strength_const) c = world.horizon_color world.arm_envtex_color = [c[0], c[1], c[2], 1.0] world.arm_envtex_strength = envmap_strength_const['float'] # Clear to color if no texture or sky is provided if '_EnvSky' not in wrd.world_defs and '_EnvTex' not in wrd.world_defs: if '_EnvImg' not in wrd.world_defs: wrd.world_defs += '_EnvCol' # Irradiance json file name world.arm_envtex_name = wname world.arm_envtex_irr_name = wname write_probes.write_color_irradiance(wname, world.arm_envtex_color) # film_transparent if bpy.context.scene != None and bpy.context.scene.cycles != None and bpy.context.scene.cycles.film_transparent: wrd.world_defs += '_EnvTransp' wrd.world_defs += '_EnvCol' # Clouds enabled if rpdat.arm_clouds: wrd.world_defs += '_EnvClouds' # Screen-space ray-traced shadows if rpdat.arm_ssrs: wrd.world_defs += '_SSRS' if wrd.arm_two_sided_area_lamp: wrd.world_defs += '_TwoSidedAreaLamp' # Store contexts if rpdat.rp_hdr == False: wrd.world_defs += '_LDR' # Alternative models if rpdat.arm_diffuse_model == 'OrenNayar': wrd.world_defs += '_OrenNayar' # TODO: Lamp texture test.. if wrd.arm_lamp_texture != '': wrd.world_defs += '_LampColTex' if wrd.arm_lamp_ies_texture != '': wrd.world_defs += '_LampIES' assets.add_embedded_data('iestexture.png') if wrd.arm_lamp_clouds_texture != '': wrd.world_defs += '_LampClouds' assets.add_embedded_data('cloudstexture.png') voxelgi = False voxelao = False if rpdat.rp_renderer == 'Deferred': assets.add_khafile_def('arm_deferred') # Shadows if rpdat.rp_shadowmap_cascades != '1' and rpdat.rp_gi == 'Off': wrd.world_defs += '_CSM' assets.add_khafile_def('arm_csm') if rpdat.rp_shadowmap == 'Off': wrd.world_defs += '_NoShadows' assets.add_khafile_def('arm_no_shadows') # GI if rpdat.rp_gi == 'Voxel GI': voxelgi = True elif rpdat.rp_gi == 'Voxel AO': voxelao = True # SS # if rpdat.rp_dfrs: # wrd.world_defs += '_DFRS' # assets.add_khafile_def('arm_sdf') # if rpdat.rp_dfao: # wrd.world_defs += '_DFAO' # assets.add_khafile_def('arm_sdf') # if rpdat.rp_dfgi: # wrd.world_defs += '_DFGI' # assets.add_khafile_def('arm_sdf') # wrd.world_defs += '_Rad' # Always do radiance for gi # wrd.world_defs += '_Irr' if rpdat.rp_ssgi == 'RTGI' or rpdat.rp_ssgi == 'RTAO': if rpdat.rp_ssgi == 'RTGI': wrd.world_defs += '_RTGI' if wrd.arm_ssgi_rays == '9': wrd.world_defs += '_SSGICone9' if rpdat.rp_autoexposure: wrd.world_defs += '_AutoExposure' if voxelgi or voxelao: assets.add_khafile_def('arm_voxelgi') if rpdat.arm_voxelgi_revoxelize: assets.add_khafile_def('arm_voxelgi_revox') if rpdat.arm_voxelgi_camera: wrd.world_defs += '_VoxelGICam' if voxelgi and wrd.arm_voxelgi_diff_cones == '5': wrd.world_defs += '_VoxelGICone5' if voxelao and wrd.arm_voxelgi_ao_cones == '9': wrd.world_defs += '_VoxelAOCone9' wrd.world_defs += '_Rad' # Always do radiance for voxels wrd.world_defs += '_Irr' if voxelgi: assets.add_khafile_def('arm_voxelgi') if rpdat.arm_voxelgi_shadows: wrd.world_defs += '_VoxelGIDirect' wrd.world_defs += '_VoxelGIShadow' if rpdat.arm_voxelgi_refraction: wrd.world_defs += '_VoxelGIDirect' wrd.world_defs += '_VoxelGIRefract' if rpdat.arm_voxelgi_emission: wrd.world_defs += '_VoxelGIEmission' wrd.world_defs += '_VoxelGI' elif voxelao: wrd.world_defs += '_VoxelAO' if arm.utils.get_gapi().startswith( 'direct3d'): # Flip Y axis in drawQuad command wrd.world_defs += '_InvY' # Area lamps for lamp in bpy.data.lamps: if lamp.type == 'AREA': wrd.world_defs += '_LTC' assets.add_khafile_def('arm_ltc') break # Data will be written after render path has been processed to gather all defines return output
def add_world_defs(): wrd = bpy.data.worlds['Arm'] rpdat = arm.utils.get_rp() # Screen-space ray-traced shadows if rpdat.arm_ssrs: wrd.world_defs += '_SSRS' if rpdat.arm_two_sided_area_light: wrd.world_defs += '_TwoSidedAreaLight' # Store contexts if rpdat.rp_hdr == False: wrd.world_defs += '_LDR' # Alternative models if rpdat.arm_diffuse_model == 'OrenNayar': wrd.world_defs += '_OrenNayar' # TODO: Light texture test.. if wrd.arm_light_texture != '': wrd.world_defs += '_LightColTex' if wrd.arm_light_ies_texture != '': wrd.world_defs += '_LightIES' assets.add_embedded_data('iestexture.png') if wrd.arm_light_clouds_texture != '': wrd.world_defs += '_LightClouds' assets.add_embedded_data('cloudstexture.png') if rpdat.rp_renderer == 'Deferred': assets.add_khafile_def('arm_deferred') wrd.world_defs += '_Deferred' # GI voxelgi = False voxelao = False has_voxels = arm.utils.voxel_support() if has_voxels: if rpdat.rp_gi == 'Voxel GI': voxelgi = True elif rpdat.rp_gi == 'Voxel AO': voxelao = True # Shadows if rpdat.rp_shadowmap == 'Off': wrd.world_defs += '_NoShadows' assets.add_khafile_def('arm_no_shadows') else: if rpdat.rp_shadowmap_cascades != '1': if voxelgi: log.warn( 'Disabling shadow cascades - Voxel GI does not support cascades yet' ) else: wrd.world_defs += '_CSM' assets.add_khafile_def('arm_csm') # SS # if rpdat.rp_dfrs: # wrd.world_defs += '_DFRS' # assets.add_khafile_def('arm_sdf') # if rpdat.rp_dfao: # wrd.world_defs += '_DFAO' # assets.add_khafile_def('arm_sdf') # if rpdat.rp_dfgi: # wrd.world_defs += '_DFGI' # assets.add_khafile_def('arm_sdf') if rpdat.rp_ssgi == 'RTGI' or rpdat.rp_ssgi == 'RTAO': if rpdat.rp_ssgi == 'RTGI': wrd.world_defs += '_RTGI' if rpdat.arm_ssgi_rays == '9': wrd.world_defs += '_SSGICone9' if rpdat.rp_autoexposure: wrd.world_defs += '_AutoExposure' if voxelgi or voxelao: assets.add_khafile_def('arm_voxelgi') wrd.world_defs += '_VoxelCones' + rpdat.arm_voxelgi_cones if rpdat.arm_voxelgi_revoxelize: assets.add_khafile_def('arm_voxelgi_revox') if rpdat.arm_voxelgi_camera: wrd.world_defs += '_VoxelGICam' if rpdat.arm_voxelgi_temporal: assets.add_khafile_def('arm_voxelgi_temporal') wrd.world_defs += '_VoxelGITemporal' if voxelgi: wrd.world_defs += '_VoxelGI' assets.add_shader_external( arm.utils.get_sdk_path() + '/armory/Shaders/voxel_light/voxel_light.comp.glsl') if rpdat.arm_voxelgi_bounces != "1": assets.add_khafile_def('rp_gi_bounces={0}'.format( rpdat.arm_voxelgi_bounces)) assets.add_shader_external( arm.utils.get_sdk_path() + '/armory/Shaders/voxel_bounce/voxel_bounce.comp.glsl') if rpdat.arm_voxelgi_shadows: wrd.world_defs += '_VoxelGIDirect' wrd.world_defs += '_VoxelGIShadow' if rpdat.arm_voxelgi_refraction: wrd.world_defs += '_VoxelGIDirect' wrd.world_defs += '_VoxelGIRefract' if rpdat.rp_voxelgi_relight: assets.add_khafile_def('rp_voxelgi_relight') elif voxelao: wrd.world_defs += '_VoxelAO' if arm.utils.get_gapi().startswith( 'direct3d'): # Flip Y axis in drawQuad command wrd.world_defs += '_InvY' if arm.utils.get_legacy_shaders() and not state.is_viewport: wrd.world_defs += '_Legacy' # Area lights lights = bpy.data.lights if bpy.app.version >= (2, 80, 1) else bpy.data.lamps for light in lights: if light.type == 'AREA': wrd.world_defs += '_LTC' assets.add_khafile_def('arm_ltc') break if '_Rad' in wrd.world_defs or '_VoxelGI' in wrd.world_defs: wrd.world_defs += '_Brdf' if '_Brdf' in wrd.world_defs or '_VoxelAO' in wrd.world_defs: wrd.world_defs += '_IndPos'
def build(): assets_path = arm.utils.get_sdk_path() + 'armory/Assets/' wrd = bpy.data.worlds['Arm'] rpdat = arm.utils.get_rp() mobile_mat = rpdat.arm_material_model == 'Mobile' or rpdat.arm_material_model == 'Solid' if not mobile_mat: # Always include assets.add(assets_path + 'brdf.png') assets.add_embedded_data('brdf.png') if rpdat.rp_hdr: assets.add_khafile_def('rp_hdr') assets.add_khafile_def('rp_renderer={0}'.format(rpdat.rp_renderer)) if rpdat.rp_depthprepass: assets.add_khafile_def('rp_depthprepass') if rpdat.rp_shadowmap != 'Off': assets.add_khafile_def('rp_shadowmap') assets.add_khafile_def('rp_shadowmap_size={0}'.format( rpdat.rp_shadowmap)) assets.add_khafile_def('rp_background={0}'.format(rpdat.rp_background)) if rpdat.rp_background == 'World': if '_EnvClouds' in wrd.world_defs: assets.add(assets_path + 'noise256.png') assets.add_embedded_data('noise256.png') if rpdat.rp_render_to_texture: assets.add_khafile_def('rp_render_to_texture') if rpdat.rp_compositornodes: assets.add_khafile_def('rp_compositornodes') compo_depth = False if wrd.arm_tonemap != 'Off': wrd.compo_defs = '_CTone' + wrd.arm_tonemap if rpdat.rp_antialiasing != 'Off': wrd.compo_defs += '_CFXAA' if wrd.arm_letterbox: wrd.compo_defs += '_CLetterbox' if wrd.arm_grain: wrd.compo_defs += '_CGrain' if bpy.data.scenes[0].cycles.film_exposure != 1.0: wrd.compo_defs += '_CExposure' if wrd.arm_fog: wrd.compo_defs += '_CFog' compo_depth = True if len(bpy.data.cameras ) > 0 and bpy.data.cameras[0].dof_distance > 0.0: wrd.compo_defs += '_CDOF' compo_depth = True if compo_depth: wrd.compo_defs += '_CDepth' if wrd.arm_lens_texture != '': wrd.compo_defs += '_CLensTex' assets.add_embedded_data('lenstexture.jpg') if wrd.arm_fisheye: wrd.compo_defs += '_CFishEye' if wrd.arm_vignette: wrd.compo_defs += '_CVignette' if wrd.arm_lensflare: wrd.compo_defs += '_CGlare' assets.add_shader2('compositor_pass', 'compositor_pass') else: assets.add_shader2('copy_pass', 'copy_pass') assets.add_khafile_def('rp_antialiasing={0}'.format( rpdat.rp_antialiasing)) if rpdat.rp_antialiasing == 'SMAA' or rpdat.rp_antialiasing == 'TAA': assets.add_shader2('smaa_edge_detect', 'smaa_edge_detect') assets.add_shader2('smaa_blend_weight', 'smaa_blend_weight') assets.add_shader2('smaa_neighborhood_blend', 'smaa_neighborhood_blend') assets.add(assets_path + 'smaa_area.png') assets.add(assets_path + 'smaa_search.png') assets.add_embedded_data('smaa_area.png') assets.add_embedded_data('smaa_search.png') wrd.world_defs += '_SMAA' if rpdat.rp_antialiasing == 'TAA': assets.add_shader2('taa_pass', 'taa_pass') assets.add_shader2('copy_pass', 'copy_pass') if rpdat.rp_antialiasing == 'TAA' or rpdat.rp_motionblur == 'Object': assets.add_khafile_def('arm_veloc') wrd.world_defs += '_Veloc' if rpdat.rp_antialiasing == 'TAA': assets.add_khafile_def('arm_taa') assets.add_khafile_def('rp_supersampling={0}'.format( rpdat.rp_supersampling)) if rpdat.rp_supersampling == '4': assets.add_shader2('supersample_resolve', 'supersample_resolve') if rpdat.rp_overlays: assets.add_khafile_def('rp_overlays') if rpdat.rp_translucency: assets.add_khafile_def('rp_translucency') assets.add_shader2('translucent_resolve', 'translucent_resolve') if rpdat.rp_stereo: assets.add_khafile_def('rp_stereo') assets.add_khafile_def('arm_vr') wrd.world_defs += '_VR' assets.add(assets_path + 'vr.png') assets.add_embedded_data('vr.png') assets.add_khafile_def('rp_gi={0}'.format(rpdat.rp_gi)) if rpdat.rp_gi != 'Off': assets.add_khafile_def('rp_gi={0}'.format(rpdat.rp_gi)) assets.add_khafile_def('rp_voxelgi_resolution={0}'.format( rpdat.rp_voxelgi_resolution)) assets.add_khafile_def('rp_voxelgi_resolution_z={0}'.format( rpdat.rp_voxelgi_resolution_z)) if rpdat.rp_voxelgi_hdr: assets.add_khafile_def('rp_voxelgi_hdr') if rpdat.arm_voxelgi_shadows: assets.add_khafile_def('rp_voxelgi_shadows') if rpdat.arm_voxelgi_refraction: assets.add_khafile_def('rp_voxelgi_refraction') if rpdat.arm_rp_resolution != 'Display': assets.add_khafile_def('rp_resolution={0}'.format( rpdat.arm_rp_resolution)) assets.add_khafile_def('rp_ssgi={0}'.format(rpdat.rp_ssgi)) if rpdat.rp_ssgi != 'Off': wrd.world_defs += '_SSAO' if rpdat.rp_ssgi == 'SSAO': assets.add_shader2('ssao_pass', 'ssao_pass') assets.add_shader2('blur_edge_pass', 'blur_edge_pass') assets.add(assets_path + 'noise8.png') assets.add_embedded_data('noise8.png') else: assets.add_shader2('ssgi_pass', 'ssgi_pass') assets.add_shader2('ssgi_blur_pass', 'ssgi_blur_pass') if rpdat.rp_renderer == 'Deferred': assets.add_shader2('deferred_indirect', 'deferred_indirect') assets.add_shader2('deferred_light', 'deferred_light') assets.add_shader2('deferred_light_quad', 'deferred_light_quad') if rpdat.rp_rendercapture: assets.add_khafile_def('rp_rendercapture') assets.add_khafile_def('rp_rendercapture_format={0}'.format( wrd.rp_rendercapture_format)) assets.add_shader2('copy_pass', 'copy_pass') if rpdat.rp_volumetriclight: assets.add_khafile_def('rp_volumetriclight') assets.add_shader2('volumetric_light_quad', 'volumetric_light_quad') assets.add_shader2('volumetric_light', 'volumetric_light') assets.add_shader2('blur_edge_pass', 'blur_edge_pass') if rpdat.rp_decals: assets.add_khafile_def('rp_decals') if rpdat.rp_ocean: assets.add_khafile_def('rp_ocean') assets.add_shader2('water_pass', 'water_pass') if rpdat.rp_blending_state != 'Off': assets.add_khafile_def('rp_blending') if rpdat.rp_bloom: assets.add_khafile_def('rp_bloom') assets.add_shader2('bloom_pass', 'bloom_pass') assets.add_shader2('blur_gaus_pass', 'blur_gaus_pass') if rpdat.rp_sss: assets.add_khafile_def('rp_sss') wrd.world_defs += '_SSS' assets.add_shader2('sss_pass', 'sss_pass') if rpdat.rp_ssr: assets.add_khafile_def('rp_ssr') assets.add_shader2('ssr_pass', 'ssr_pass') assets.add_shader2('blur_adaptive_pass', 'blur_adaptive_pass') if rpdat.arm_ssr_half_res: assets.add_khafile_def('rp_ssr_half') if rpdat.rp_motionblur != 'Off': assets.add_khafile_def('rp_motionblur={0}'.format(rpdat.rp_motionblur)) assets.add_shader2('copy_pass', 'copy_pass') if rpdat.rp_motionblur == 'Camera': assets.add_shader2('motion_blur_pass', 'motion_blur_pass') else: assets.add_shader2('motion_blur_veloc_pass', 'motion_blur_veloc_pass') if rpdat.rp_compositornodes and rpdat.rp_autoexposure: assets.add_khafile_def('rp_autoexposure') if rpdat.rp_dynres: assets.add_khafile_def('rp_dynres')
def traverse_renderpath(node, node_group, render_targets, depth_buffers): # Gather linked draw geometry contexts if node.bl_idname == 'DrawMeshesNodeType': if build_node_tree.cam.renderpath_passes != '': build_node_tree.cam.renderpath_passes += '_' # Separator build_node_tree.cam.renderpath_passes += node.inputs[1].default_value # Gather defs from linked nodes if node.bl_idname == 'TAAPassNodeType' or node.bl_idname == 'MotionBlurVelocityPassNodeType' or node.bl_idname == 'SSAOReprojectPassNodeType': if preprocess_renderpath.velocity_def_added == False: assets.add_khafile_def('arm_veloc') bpy.data.worlds['Arm'].rp_defs += '_Veloc' preprocess_renderpath.velocity_def_added = True if node.bl_idname == 'TAAPassNodeType': assets.add_khafile_def('arm_taa') # bpy.data.worlds['Arm'].rp_defs += '_TAA' elif node.bl_idname == 'SMAAPassNodeType': bpy.data.worlds['Arm'].rp_defs += '_SMAA' elif node.bl_idname == 'SSSPassNodeType': bpy.data.worlds['Arm'].rp_defs += '_SSS' elif node.bl_idname == 'SSAOPassNodeType' or node.bl_idname == 'ApplySSAOPassNodeType' or node.bl_idname == 'SSAOReprojectPassNodeType': if bpy.data.worlds['Arm'].generate_ssao: # SSAO enabled bpy.data.worlds['Arm'].rp_defs += '_SSAO' elif node.bl_idname == 'DrawStereoNodeType': assets.add_khafile_def('arm_vr') bpy.data.worlds['Arm'].rp_defs += '_VR' assets.add(build_node_trees.assets_path + 'vr.png') assets.add_embedded_data('vr.png') elif node.bl_idname == 'CallFunctionNodeType': global dynRes_added fstr = node.inputs[1].default_value if not dynRes_added and fstr.startswith( 'armory.renderpath.DynamicResolutionScale'): bpy.data.worlds['Arm'].rp_defs += '_DynRes' dynRes_added = True # Collect render targets if node.bl_idname == 'SetTargetNodeType' or node.bl_idname == 'BindTargetNodeType' or node.bl_idname == 'QuadPassNodeType' or node.bl_idname == 'DrawCompositorNodeType' or node.bl_idname == 'DrawCompositorWithFXAANodeType': if node.inputs[1].is_linked: tnode = nodes.find_node_by_link(node_group, node, node.inputs[1]) parse_render_target(tnode, node_group, render_targets, depth_buffers) # Traverse loops elif node.bl_idname == 'LoopStagesNodeType' or node.bl_idname == 'LoopLampsNodeType' or node.bl_idname == 'DrawStereoNodeType': if node.outputs[1].is_linked: loop_node = nodes.find_node_by_link_from(node_group, node, node.outputs[1]) traverse_renderpath(loop_node, node_group, render_targets, depth_buffers) # Prebuilt elif node.bl_idname == 'MotionBlurPassNodeType' or node.bl_idname == 'MotionBlurVelocityPassNodeType' or node.bl_idname == 'CopyPassNodeType' or node.bl_idname == 'MatIDToDepthNodeType' or node.bl_idname == 'BlendPassNodeType' or node.bl_idname == 'CombinePassNodeType' or node.bl_idname == 'DebugNormalsPassNodeType' or node.bl_idname == 'FXAAPassNodeType' or node.bl_idname == 'SSResolveNodeType' or node.bl_idname == 'TAAPassNodeType' or node.bl_idname == 'WaterPassNodeType' or node.bl_idname == 'DeferredLightPassNodeType' or node.bl_idname == 'DeferredIndirectPassNodeType' or node.bl_idname == 'VolumetricLightPassNodeType' or node.bl_idname == 'TranslucentResolvePassNodeType': if node.inputs[1].is_linked: tnode = nodes.find_node_by_link(node_group, node, node.inputs[1]) parse_render_target(tnode, node_group, render_targets, depth_buffers) elif node.bl_idname == 'SSRPassNodeType' or node.bl_idname == 'ApplySSAOPassNodeType' or node.bl_idname == 'BloomPassNodeType' or node.bl_idname == 'SMAAPassNodeType': for i in range(1, 4): if node.inputs[i].is_linked: tnode = nodes.find_node_by_link(node_group, node, node.inputs[i]) parse_render_target(tnode, node_group, render_targets, depth_buffers) elif node.bl_idname == 'SSAOPassNodeType' or node.bl_idname == 'SSAOReprojectPassNodeType' or node.bl_idname == 'SSSPassNodeType' or node.bl_idname == 'BlurBasicPassNodeType': for i in range(1, 3): if node.inputs[i].is_linked: tnode = nodes.find_node_by_link(node_group, node, node.inputs[i]) parse_render_target(tnode, node_group, render_targets, depth_buffers) # Next stage if node.outputs[0].is_linked: stagenode = nodes.find_node_by_link_from(node_group, node, node.outputs[0]) traverse_renderpath(stagenode, node_group, render_targets, depth_buffers)
def build(): rpdat = arm.utils.get_rp() if rpdat.rp_driver != 'Armory' and arm.api.drivers[ rpdat.rp_driver]['make_rpath'] != None: arm.api.drivers[rpdat.rp_driver]['make_rpath']() return assets_path = arm.utils.get_sdk_path() + '/armory/Assets/' wrd = bpy.data.worlds['Arm'] add_world_defs() mobile_mat = rpdat.arm_material_model == 'Mobile' or rpdat.arm_material_model == 'Solid' if not mobile_mat: # Always include assets.add(assets_path + 'brdf.png') assets.add_embedded_data('brdf.png') if rpdat.rp_hdr: assets.add_khafile_def('rp_hdr') assets.add_khafile_def('rp_renderer={0}'.format(rpdat.rp_renderer)) if rpdat.rp_depthprepass: assets.add_khafile_def('rp_depthprepass') if rpdat.rp_shadowmap != 'Off': assets.add_khafile_def('rp_shadowmap') assets.add_khafile_def('rp_shadowmap_size={0}'.format( rpdat.rp_shadowmap)) assets.add_khafile_def('rp_background={0}'.format(rpdat.rp_background)) if rpdat.rp_background == 'World': assets.add_shader_pass('world_pass') if '_EnvClouds' in wrd.world_defs: assets.add(assets_path + 'noise256.png') assets.add_embedded_data('noise256.png') if rpdat.rp_renderer == 'Deferred' and not rpdat.rp_compositornodes: assets.add_shader_pass('copy_pass') if rpdat.rp_renderer == 'Forward' and not rpdat.rp_compositornodes and rpdat.rp_render_to_texture: assets.add_shader_pass('copy_pass') if rpdat.rp_render_to_texture: assets.add_khafile_def('rp_render_to_texture') if rpdat.rp_compositornodes: assets.add_khafile_def('rp_compositornodes') compo_depth = False if rpdat.arm_tonemap != 'Off': wrd.compo_defs = '_CTone' + rpdat.arm_tonemap if rpdat.rp_antialiasing == 'FXAA': wrd.compo_defs += '_CFXAA' if rpdat.arm_letterbox: wrd.compo_defs += '_CLetterbox' if rpdat.arm_grain: wrd.compo_defs += '_CGrain' if rpdat.arm_sharpen: wrd.compo_defs += '_CSharpen' if bpy.data.scenes[0].cycles.film_exposure != 1.0: wrd.compo_defs += '_CExposure' if rpdat.arm_fog: wrd.compo_defs += '_CFog' compo_depth = True if len(bpy.data.cameras ) > 0 and bpy.data.cameras[0].dof_distance > 0.0: wrd.compo_defs += '_CDOF' compo_depth = True if compo_depth: wrd.compo_defs += '_CDepth' assets.add_khafile_def('rp_compositordepth') if rpdat.arm_lens_texture != '': wrd.compo_defs += '_CLensTex' assets.add_embedded_data('lenstexture.jpg') if rpdat.arm_fisheye: wrd.compo_defs += '_CFishEye' if rpdat.arm_vignette: wrd.compo_defs += '_CVignette' if rpdat.arm_lensflare: wrd.compo_defs += '_CGlare' if rpdat.arm_lut_texture != '': wrd.compo_defs += '_CLUT' assets.add_embedded_data('luttexture.jpg') if '_CDOF' in wrd.compo_defs or '_CFXAA' in wrd.compo_defs or '_CSharpen' in wrd.compo_defs: wrd.compo_defs += '_CTexStep' if '_CDOF' in wrd.compo_defs or '_CFog' in wrd.compo_defs or '_CGlare' in wrd.compo_defs: wrd.compo_defs += '_CCameraProj' assets.add_shader_pass('compositor_pass') assets.add_khafile_def('rp_antialiasing={0}'.format( rpdat.rp_antialiasing)) if rpdat.rp_antialiasing == 'SMAA' or rpdat.rp_antialiasing == 'TAA': assets.add_shader_pass('smaa_edge_detect') assets.add_shader_pass('smaa_blend_weight') assets.add_shader_pass('smaa_neighborhood_blend') assets.add(assets_path + 'smaa_area.png') assets.add(assets_path + 'smaa_search.png') assets.add_embedded_data('smaa_area.png') assets.add_embedded_data('smaa_search.png') wrd.world_defs += '_SMAA' if rpdat.rp_antialiasing == 'TAA': assets.add_shader_pass('taa_pass') assets.add_shader_pass('copy_pass') if rpdat.rp_antialiasing == 'TAA' or rpdat.rp_motionblur == 'Object': assets.add_khafile_def('arm_veloc') wrd.world_defs += '_Veloc' if rpdat.rp_antialiasing == 'TAA': assets.add_khafile_def('arm_taa') assets.add_khafile_def('rp_supersampling={0}'.format( rpdat.rp_supersampling)) if rpdat.rp_supersampling == '4': assets.add_shader_pass('supersample_resolve') if rpdat.rp_overlays: assets.add_khafile_def('rp_overlays') if rpdat.rp_translucency: assets.add_khafile_def('rp_translucency') assets.add_shader_pass('translucent_resolve') if rpdat.rp_stereo: assets.add_khafile_def('rp_stereo') assets.add_khafile_def('arm_vr') wrd.world_defs += '_VR' assets.add(assets_path + 'vr.png') assets.add_embedded_data('vr.png') rp_gi = rpdat.rp_gi has_voxels = arm.utils.voxel_support() if not has_voxels: rp_gi = 'Off' assets.add_khafile_def('rp_gi={0}'.format(rp_gi)) if rpdat.rp_gi != 'Off': if has_voxels: assets.add_khafile_def('rp_gi={0}'.format(rpdat.rp_gi)) assets.add_khafile_def('rp_voxelgi_resolution={0}'.format( rpdat.rp_voxelgi_resolution)) assets.add_khafile_def('rp_voxelgi_resolution_z={0}'.format( rpdat.rp_voxelgi_resolution_z)) if rpdat.rp_voxelgi_hdr: assets.add_khafile_def('rp_voxelgi_hdr') if rpdat.arm_voxelgi_shadows: assets.add_khafile_def('rp_voxelgi_shadows') if rpdat.arm_voxelgi_refraction: assets.add_khafile_def('rp_voxelgi_refraction') else: log.warn( 'Disabling Voxel GI - unsupported target - use Krom instead') if rpdat.arm_rp_resolution == 'Custom': assets.add_khafile_def('rp_resolution_filter={0}'.format( rpdat.arm_rp_resolution_filter)) assets.add_khafile_def('rp_ssgi={0}'.format(rpdat.rp_ssgi)) if rpdat.rp_ssgi != 'Off': wrd.world_defs += '_SSAO' if rpdat.rp_ssgi == 'SSAO': assets.add_shader_pass('ssao_pass') assets.add_shader_pass('blur_edge_pass') assets.add(assets_path + 'noise8.png') assets.add_embedded_data('noise8.png') else: assets.add_shader_pass('ssgi_pass') assets.add_shader_pass('ssgi_blur_pass') if rpdat.rp_renderer == 'Deferred': assets.add_shader_pass('deferred_indirect') assets.add_shader_pass('deferred_light') assets.add_shader_pass('deferred_light_quad') if rpdat.rp_volumetriclight: assets.add_khafile_def('rp_volumetriclight') assets.add_shader_pass('volumetric_light_quad') assets.add_shader_pass('volumetric_light') assets.add_shader_pass('blur_bilat_pass') assets.add_shader_pass('blur_bilat_blend_pass') assets.add(assets_path + 'blue_noise64.png') assets.add_embedded_data('blue_noise64.png') if rpdat.rp_decals: assets.add_khafile_def('rp_decals') if rpdat.rp_ocean: assets.add_khafile_def('rp_ocean') assets.add_shader_pass('water_pass') if rpdat.rp_blending: assets.add_khafile_def('rp_blending') if rpdat.rp_bloom: assets.add_khafile_def('rp_bloom') assets.add_shader_pass('bloom_pass') assets.add_shader_pass('blur_gaus_pass') if rpdat.rp_sss: assets.add_khafile_def('rp_sss') wrd.world_defs += '_SSS' assets.add_shader_pass('sss_pass') if rpdat.rp_ssr: assets.add_khafile_def('rp_ssr') assets.add_shader_pass('ssr_pass') assets.add_shader_pass('blur_adaptive_pass') if rpdat.arm_ssr_half_res: assets.add_khafile_def('rp_ssr_half') if rpdat.rp_ssr_z_only: wrd.world_defs += '_SSRZOnly' if rpdat.rp_motionblur != 'Off': assets.add_khafile_def('rp_motionblur={0}'.format(rpdat.rp_motionblur)) assets.add_shader_pass('copy_pass') if rpdat.rp_motionblur == 'Camera': assets.add_shader_pass('motion_blur_pass') else: assets.add_shader_pass('motion_blur_veloc_pass') if rpdat.rp_compositornodes and rpdat.rp_autoexposure: assets.add_khafile_def('rp_autoexposure') if rpdat.rp_dynres: assets.add_khafile_def('rp_dynres') if rpdat.arm_soft_shadows == 'On': if rpdat.rp_shadowmap_cascades == '1': assets.add_shader_pass('dilate_pass') assets.add_shader_pass('visibility_pass') assets.add_shader_pass('blur_shadow_pass') assets.add_khafile_def('rp_soft_shadows') wrd.world_defs += '_SoftShadows' if rpdat.arm_soft_shadows_penumbra != 1: wrd.world_defs += '_PenumbraScale' else: log.warn( 'Disabling soft shadows - "Armory Render Path - Cascades" requires to be set to 1 for now' ) gbuffer2_direct = '_SSS' in wrd.world_defs or '_Hair' in wrd.world_defs or rpdat.arm_voxelgi_refraction gbuffer2 = '_Veloc' in wrd.world_defs or gbuffer2_direct if gbuffer2: assets.add_khafile_def('rp_gbuffer2') wrd.world_defs += '_gbuffer2' if gbuffer2_direct: assets.add_khafile_def('rp_gbuffer2_direct') wrd.world_defs += '_gbuffer2direct' if callback != None: callback()
def add_world_defs(): wrd = bpy.data.worlds['Arm'] rpdat = arm.utils.get_rp() # Screen-space ray-traced shadows if rpdat.arm_ssrs: wrd.world_defs += '_SSRS' if wrd.arm_two_sided_area_lamp: wrd.world_defs += '_TwoSidedAreaLamp' # Store contexts if rpdat.rp_hdr == False: wrd.world_defs += '_LDR' # Alternative models if rpdat.arm_diffuse_model == 'OrenNayar': wrd.world_defs += '_OrenNayar' # TODO: Lamp texture test.. if wrd.arm_lamp_texture != '': wrd.world_defs += '_LampColTex' if wrd.arm_lamp_ies_texture != '': wrd.world_defs += '_LampIES' assets.add_embedded_data('iestexture.png') if wrd.arm_lamp_clouds_texture != '': wrd.world_defs += '_LampClouds' assets.add_embedded_data('cloudstexture.png') if rpdat.rp_renderer == 'Deferred': assets.add_khafile_def('arm_deferred') # GI voxelgi = False voxelao = False has_voxels = arm.utils.voxel_support() if has_voxels: if rpdat.rp_gi == 'Voxel GI': voxelgi = True elif rpdat.rp_gi == 'Voxel AO': voxelao = True # Shadows if rpdat.rp_shadowmap_cascades != '1': if voxelgi: log.warn( 'Disabling shadow cascades - Voxel GI does not support cascades yet' ) else: wrd.world_defs += '_CSM' assets.add_khafile_def('arm_csm') if rpdat.rp_shadowmap == 'Off': wrd.world_defs += '_NoShadows' assets.add_khafile_def('arm_no_shadows') # SS # if rpdat.rp_dfrs: # wrd.world_defs += '_DFRS' # assets.add_khafile_def('arm_sdf') # if rpdat.rp_dfao: # wrd.world_defs += '_DFAO' # assets.add_khafile_def('arm_sdf') # if rpdat.rp_dfgi: # wrd.world_defs += '_DFGI' # assets.add_khafile_def('arm_sdf') if rpdat.rp_ssgi == 'RTGI' or rpdat.rp_ssgi == 'RTAO': if rpdat.rp_ssgi == 'RTGI': wrd.world_defs += '_RTGI' if wrd.arm_ssgi_rays == '9': wrd.world_defs += '_SSGICone9' if rpdat.rp_autoexposure: wrd.world_defs += '_AutoExposure' if voxelgi or voxelao: assets.add_khafile_def('arm_voxelgi') wrd.world_defs += '_VoxelCones' + wrd.arm_voxelgi_cones if rpdat.arm_voxelgi_revoxelize: assets.add_khafile_def('arm_voxelgi_revox') if rpdat.arm_voxelgi_camera: wrd.world_defs += '_VoxelGICam' if rpdat.arm_voxelgi_temporal: assets.add_khafile_def('arm_voxelgi_temporal') wrd.world_defs += '_VoxelGITemporal' if voxelgi: wrd.world_defs += '_VoxelGI' if rpdat.arm_voxelgi_shadows: wrd.world_defs += '_VoxelGIDirect' wrd.world_defs += '_VoxelGIShadow' if rpdat.arm_voxelgi_refraction: wrd.world_defs += '_VoxelGIDirect' wrd.world_defs += '_VoxelGIRefract' if rpdat.arm_voxelgi_emission: wrd.world_defs += '_VoxelGIEmission' elif voxelao: wrd.world_defs += '_VoxelAO' if arm.utils.get_gapi().startswith( 'direct3d'): # Flip Y axis in drawQuad command wrd.world_defs += '_InvY' # Area lamps for lamp in bpy.data.lamps: if lamp.type == 'AREA': wrd.world_defs += '_LTC' assets.add_khafile_def('arm_ltc') break if '_Rad' in wrd.world_defs or '_VoxelGI' in wrd.world_defs: wrd.world_defs += '_Brdf' if '_Brdf' in wrd.world_defs or '_VoxelAO' in wrd.world_defs: wrd.world_defs += '_IndPos'