Ejemplo n.º 1
0
    def execute(self, context):
        sdk_path = armutils.get_sdk_path()
        project_path = armutils.get_fp()
        pkg = bpy.data.worlds['Arm'].arm_project_package
        item = context.object.my_traitlist[context.object.traitlist_index]
        source_hx_path = sdk_path + '/armory/Sources/armory/trait/' + item.class_name_prop + '.hx'
        target_hx_path = project_path + '/Sources/' + pkg + '/' + item.class_name_prop + '.hx'

        if not os.path.isfile(target_hx_path):
            # Rewrite package and copy
            sf = open(source_hx_path)
            sf.readline()
            tf = open(target_hx_path, 'w')
            tf.write('package ' + pkg + ';\n')
            shutil.copyfileobj(sf, tf)
            sf.close()
            tf.close()
            armutils.fetch_script_names()

        # From bundled to script
        item.type_prop = 'Haxe Script'

        # Edit in Kode Studio
        bpy.ops.arm.edit_script('EXEC_DEFAULT')

        return {'FINISHED'}
Ejemplo n.º 2
0
def on_compiled(mode): # build, play, play_viewport, publish
    log.clear()
    sdk_path = armutils.get_sdk_path()

    # Print info
    if mode == 'publish':
        target_name = make_utils.get_kha_target(bpy.data.worlds['Arm'].arm_project_target)
        print('Project published')
        files_path = armutils.get_fp() + '/build/' + target_name
        if target_name == 'html5':
            print('HTML5 files are located in ' + files_path)
        elif target_name == 'ios' or target_name == 'osx': # TODO: to macos
            print('XCode project files are located in ' + files_path + '-build')
        elif target_name == 'windows':
            print('VisualStudio 2015 project files are located in ' + files_path + '-build')
        elif target_name == 'android-native':
            print('Android Studio project files are located in ' + files_path + '-build')
        else:
            print('Makefiles are located in ' + files_path + '-build')
        return

    # Launch project in new window
    elif mode =='play':
        wrd = bpy.data.worlds['Arm']
        if wrd.arm_play_runtime == 'Electron':
            electron_app_path = './build/electron.js'

            if armutils.get_os() == 'win':
                electron_path = sdk_path + 'win32/Kode Studio.exe'
            elif armutils.get_os() == 'mac':
                electron_path = sdk_path + 'Kode Studio.app/Contents/MacOS/Electron'
            else:
                electron_path = sdk_path + 'linux64/kodestudio'

            state.playproc = subprocess.Popen([electron_path, '--chromedebug', '--remote-debugging-port=9222', '--enable-logging', electron_app_path], stderr=subprocess.PIPE)
            watch_play()
        elif wrd.arm_play_runtime == 'Browser':
            # Start server
            os.chdir(armutils.get_fp())
            t = threading.Thread(name='localserver', target=lib.server.run)
            t.daemon = True
            t.start()
            html5_app_path = 'http://localhost:8040/build/html5'
            webbrowser.open(html5_app_path)
        elif wrd.arm_play_runtime == 'Krom':
            if armutils.get_os() == 'win':
                krom_location = sdk_path + '/win32/Krom/win32'
                krom_path = krom_location + '/Krom.exe'
            elif armutils.get_os() == 'mac':
                krom_location = sdk_path + '/Kode Studio.app/Contents/Krom/macos/Krom.app/Contents/MacOS'
                krom_path = krom_location + '/Krom'
            else:
                krom_location = sdk_path + '/linux64/Krom/linux'
                krom_path = krom_location + '/Krom'
            os.chdir(krom_location)
            state.playproc = subprocess.Popen([krom_path, armutils.get_fp() + '/build/window/krom', armutils.get_fp() + '/build/window/krom-resources'], stderr=subprocess.PIPE)
            watch_play()
Ejemplo n.º 3
0
Archivo: make.py Proyecto: daela/armory
def on_compiled(mode): # build, play, play_viewport, publish
    log.clear()
    sdk_path = armutils.get_sdk_path()
    wrd = bpy.data.worlds['Arm']

    # Print info
    if mode == 'publish':
        target_name = make_utils.get_kha_target(wrd.arm_project_target)
        print('Project published')
        files_path = armutils.get_fp() + '/build/' + target_name
        if target_name == 'html5':
            print('HTML5 files are located in ' + files_path)
        elif target_name == 'ios' or target_name == 'osx': # TODO: to macos
            print('XCode project files are located in ' + files_path + '-build')
        elif target_name == 'windows':
            print('VisualStudio 2015 project files are located in ' + files_path + '-build')
        elif target_name == 'android-native':
            print('Android Studio project files are located in ' + files_path + '-build/' + wrd.arm_project_name)
        else:
            print('Makefiles are located in ' + files_path + '-build')
        return

    # Launch project in new window
    elif mode =='play':
        if wrd.arm_play_runtime == 'Electron':
            electron_app_path = './build/electron.js'

            if armutils.get_os() == 'win':
                electron_path = sdk_path + 'win32/Kode Studio.exe'
            elif armutils.get_os() == 'mac':
                electron_path = sdk_path + 'Kode Studio.app/Contents/MacOS/Electron'
            else:
                electron_path = sdk_path + 'linux64/kodestudio'

            state.playproc = subprocess.Popen([electron_path, '--chromedebug', '--remote-debugging-port=9222', '--enable-logging', electron_app_path], stderr=subprocess.PIPE)
            watch_play()
        elif wrd.arm_play_runtime == 'Browser':
            # Start server
            os.chdir(armutils.get_fp())
            t = threading.Thread(name='localserver', target=lib.server.run)
            t.daemon = True
            t.start()
            html5_app_path = 'http://localhost:8040/build/html5'
            webbrowser.open(html5_app_path)
        elif wrd.arm_play_runtime == 'Krom':
            if armutils.get_os() == 'win':
                krom_location = sdk_path + '/win32/Krom/win32'
                krom_path = krom_location + '/Krom.exe'
            elif armutils.get_os() == 'mac':
                krom_location = sdk_path + '/Kode Studio.app/Contents/Krom/macos/Krom.app/Contents/MacOS'
                krom_path = krom_location + '/Krom'
            else:
                krom_location = sdk_path + '/linux64/Krom/linux'
                krom_path = krom_location + '/Krom'
            os.chdir(krom_location)
            state.playproc = subprocess.Popen([krom_path, armutils.get_fp() + '/build/window/krom', armutils.get_fp() + '/build/window/krom-resources'], stderr=subprocess.PIPE)
            watch_play()
Ejemplo n.º 4
0
def kode_studio():
    sdk_path = armutils.get_sdk_path()
    project_path = armutils.get_fp()

    if armutils.get_os() == 'win':
        kode_path = sdk_path + '/win32/Kode Studio.exe'
        subprocess.Popen([kode_path, armutils.get_fp()])
    elif armutils.get_os() == 'mac':
        kode_path = '"' + sdk_path + '/Kode Studio.app/Contents/MacOS/Electron"'
        subprocess.Popen([kode_path + ' ' + armutils.get_fp()], shell=True)
    else:
        kode_path = sdk_path + '/linux64/kodestudio'
        subprocess.Popen([kode_path, armutils.get_fp()])
Ejemplo n.º 5
0
def kode_studio():
    sdk_path = armutils.get_sdk_path()
    project_path = armutils.get_fp()

    if armutils.get_os() == 'win':
        kode_path = sdk_path + '/win32/Kode Studio.exe'
        subprocess.Popen([kode_path, armutils.get_fp()])
    elif armutils.get_os() == 'mac':
        kode_path = '"' + sdk_path + '/Kode Studio.app/Contents/MacOS/Electron"'
        subprocess.Popen([kode_path + ' ' + armutils.get_fp()], shell=True)
    else:
        kode_path = sdk_path + '/linux64/kodestudio'
        subprocess.Popen([kode_path, armutils.get_fp()])
Ejemplo n.º 6
0
    def execute(self, context):
        project_path = armutils.get_fp()
        item = context.object.my_traitlist[context.object.traitlist_index]  
        hx_path = project_path + '/Sources/' + bpy.data.worlds['Arm'].arm_project_package + '/' + item.class_name_prop + '.hx'

        sdk_path = armutils.get_sdk_path()
        if armutils.get_os() == 'win':
            kode_path = sdk_path + '/win32/Kode Studio.exe'
            subprocess.Popen([kode_path, armutils.get_fp(), hx_path])
        elif armutils.get_os() == 'mac':
            kode_path = '"' + sdk_path + '/Kode Studio.app/Contents/MacOS/Electron"'
            subprocess.Popen([kode_path + ' ' + armutils.get_fp() + ' ' + hx_path], shell=True)
        else:
            kode_path = sdk_path + '/linux64/kodestudio'
            subprocess.Popen([kode_path, armutils.get_fp(), hx_path])
        
        return{'FINISHED'}
Ejemplo n.º 7
0
def load_library(asset_name, rename=None):
    sdk_path = armutils.get_sdk_path()
    data_path = sdk_path + '/armory/blender/data/data.blend'
    data_names = [asset_name]

    # Remove old
    if rename != None and rename in bpy.data.node_groups and asset_name != 'Armory PBR':
        bpy.data.node_groups.remove(bpy.data.node_groups[rename],
                                    do_unlink=True)

    # Import
    data_refs = data_names.copy()
    with bpy.data.libraries.load(data_path,
                                 link=False) as (data_from, data_to):
        data_to.node_groups = data_refs

    for ref in data_refs:
        ref.use_fake_user = True
        if rename != None:
            ref.name = rename
Ejemplo n.º 8
0
    def execute(self, context):
        project_path = armutils.get_fp()
        item = context.object.my_traitlist[context.object.traitlist_index]
        hx_path = project_path + '/Sources/' + bpy.data.worlds[
            'Arm'].arm_project_package + '/' + item.class_name_prop + '.hx'

        sdk_path = armutils.get_sdk_path()
        if armutils.get_os() == 'win':
            kode_path = sdk_path + '/win32/Kode Studio.exe'
            subprocess.Popen([kode_path, armutils.get_fp(), hx_path])
        elif armutils.get_os() == 'mac':
            kode_path = '"' + sdk_path + '/Kode Studio.app/Contents/MacOS/Electron"'
            subprocess.Popen(
                [kode_path + ' ' + armutils.get_fp() + ' ' + hx_path],
                shell=True)
        else:
            kode_path = sdk_path + '/linux64/kodestudio'
            subprocess.Popen([kode_path, armutils.get_fp(), hx_path])

        return {'FINISHED'}
Ejemplo n.º 9
0
def write_probes(image_filepath,
                 disable_hdr,
                 cached_num_mips,
                 generate_radiance=True):
    envpath = 'build/compiled/Assets/envmaps'

    if not os.path.exists(envpath):
        os.makedirs(envpath)

    base_name = armutils.extract_filename(image_filepath).rsplit('.', 1)[0]

    # Assets to be generated
    output_file_irr = envpath + '/' + base_name + '_irradiance'
    if generate_radiance:
        output_file_rad = envpath + '/' + base_name + '_radiance'
        rad_format = 'jpg' if disable_hdr else 'hdr'

    # Radiance & irradiance exists, keep cache
    basep = envpath + '/' + base_name
    if os.path.exists(basep + '_irradiance.arm'):
        if not generate_radiance or os.path.exists(basep + '_radiance_0.' +
                                                   rad_format):
            add_irr_assets(output_file_irr)
            if generate_radiance:
                add_rad_assets(output_file_rad, rad_format, cached_num_mips)
            return cached_num_mips

    # Get paths
    sdk_path = armutils.get_sdk_path()

    if armutils.get_os() == 'win':
        cmft_path = sdk_path + '/armory/tools/cmft/cmft.exe'
        kraffiti_path = sdk_path + '/win32/Kha/Kore/Tools/kraffiti/kraffiti.exe'
    elif armutils.get_os() == 'mac':
        cmft_path = '"' + sdk_path + '/armory/tools/cmft/cmft-osx"'
        kraffiti_path = '"' + sdk_path + '/Kode Studio.app/Contents/Kha/Kore/Tools/kraffiti/kraffiti-osx"'
    else:
        cmft_path = '"' + sdk_path + '/armory/tools/cmft/cmft-linux64"'
        kraffiti_path = '"' + sdk_path + '/linux64/Kha/Kore/Tools/kraffiti/kraffiti-linux64"'

    output_gama_numerator = '1.0' if disable_hdr else '2.2'
    input_file = armutils.safe_assetpath(image_filepath)

    # Scale map
    wrd = bpy.data.worlds['Arm']
    target_w = int(wrd.generate_radiance_size)
    target_h = int(target_w / 2)
    scaled_file = output_file_rad + '.' + rad_format

    if armutils.get_os() == 'win':
        output = subprocess.check_output([ \
            kraffiti_path,
            'from=' + input_file.replace(' ', '\ '),
            'to=' + scaled_file.replace(' ', '\ '),
            'format=' + rad_format,
            'width=' + str(target_w),
            'height=' + str(target_h)])
    else:
        output = subprocess.check_output([ \
            kraffiti_path + \
            ' from="' + input_file + '"' + \
            ' to="' + scaled_file + '"' + \
            ' format=' + rad_format + \
            ' width=' + str(target_w) + \
            ' height=' + str(target_h)], shell=True)

    # Generate irradiance
    # gama_options = ''
    # if disable_hdr:
    # gama_options = \
    # ' --inputGammaNumerator 2.2' + \
    # ' --inputGammaDenominator 1.0' + \
    # ' --outputGammaNumerator 1.0' + \
    # ' --outputGammaDenominator ' + output_gama_numerator

    # Irradiance spherical harmonics
    if armutils.get_os() == 'win':
        subprocess.call([ \
            cmft_path,
            '--input', scaled_file.replace(' ', '\ '),
            '--filter', 'shcoeffs',
            #gama_options + \
            '--outputNum', '1',
            '--output0', output_file_irr])
    else:
        subprocess.call([ \
            cmft_path + \
            ' --input ' + '"' + scaled_file + '"' + \
            ' --filter shcoeffs' + \
            #gama_options + \
            ' --outputNum 1' + \
            ' --output0 ' + output_file_irr], shell=True)

    sh_to_json(output_file_irr)
    add_irr_assets(output_file_irr)

    # Mip-mapped radiance
    if generate_radiance == False:
        return cached_num_mips

    # 4096 = 256 face
    # 2048 = 128 face
    # 1024 = 64 face
    face_size = target_w / 8
    if target_w == 2048:
        mip_count = 9
    elif target_w == 1024:
        mip_count = 8
    else:
        mip_count = 7

    use_opencl = 'true' if wrd.arm_gpu_processing else 'false'

    if armutils.get_os() == 'win':
        subprocess.call([ \
            cmft_path,
            '--input', input_file.replace(' ', '\ '),
            '--filter', 'radiance',
            '--dstFaceSize', str(face_size),
            '--srcFaceSize', str(face_size),
            '--excludeBase', 'false',
            # '--mipCount', str(mip_count),
            '--glossScale', '7',
            '--glossBias', '3',
            '--lightingModel', 'blinnbrdf',
            '--edgeFixup', 'none',
            '--numCpuProcessingThreads', '4',
            '--useOpenCL', use_opencl,
            '--clVendor', 'anyGpuVendor',
            '--deviceType', 'gpu',
            '--deviceIndex', '0',
            '--generateMipChain', 'true',
            '--inputGammaNumerator', '2.2',
            '--inputGammaDenominator', '1.0',
            '--outputGammaNumerator', '1.0',
            '--outputGammaDenominator', output_gama_numerator,
            '--outputNum', '1',
            '--output0', output_file_rad.replace(' ', '\ '),
            '--output0params', 'hdr,rgbe,latlong'])
    else:
        subprocess.call([ \
            cmft_path + \
            ' --input "' + input_file + '"' + \
            ' --filter radiance' + \
            ' --dstFaceSize ' + str(face_size) + \
            ' --srcFaceSize ' + str(face_size) + \
            ' --excludeBase false' + \
            #' --mipCount ' + str(mip_count) + \
            ' --glossScale 7' + \
            ' --glossBias 3' + \
            ' --lightingModel blinnbrdf' + \
            ' --edgeFixup none' + \
            ' --numCpuProcessingThreads 4' + \
            ' --useOpenCL ' + use_opencl + \
            ' --clVendor anyGpuVendor' + \
            ' --deviceType gpu' + \
            ' --deviceIndex 0' + \
            ' --generateMipChain true' + \
            ' --inputGammaNumerator 2.2' + \
            ' --inputGammaDenominator 1.0' + \
            ' --outputGammaNumerator 1.0' + \
            ' --outputGammaDenominator ' + output_gama_numerator + \
            ' --outputNum 1' + \
            ' --output0 "' + output_file_rad + '"' + \
            ' --output0params hdr,rgbe,latlong'], shell=True)

    # Remove size extensions in file name
    mip_w = int(face_size * 4)
    mip_base = output_file_rad + '_'
    mip_num = 0
    while mip_w >= 4:
        mip_name = mip_base + str(mip_num)
        os.rename(
            mip_name + '_' + str(mip_w) + 'x' + str(int(mip_w / 2)) + '.hdr',
            mip_name + '.hdr')
        mip_w = int(mip_w / 2)
        mip_num += 1

    # Append mips
    generated_files = []
    for i in range(0, mip_count):
        generated_files.append(output_file_rad + '_' + str(i))

    # Convert to jpgs
    if disable_hdr is True:
        for f in generated_files:
            if armutils.get_os() == 'win':
                subprocess.call([ \
                    kraffiti_path,
                    'from=' + f + '.hdr',
                    'to=' + f + '.jpg',
                    'format=jpg'])
            else:
                subprocess.call([ \
                    kraffiti_path + \
                    ' from=' + f + '.hdr' + \
                    ' to=' + f + '.jpg' + \
                    ' format=jpg'], shell=True)
            os.remove(f + '.hdr')

    # Scale from (4x2 to 1x1>
    for i in range(0, 2):
        last = generated_files[-1]
        out = output_file_rad + '_' + str(mip_count + i)
        if armutils.get_os() == 'win':
            subprocess.call([ \
                kraffiti_path,
                'from=' + last + '.' + rad_format,
                'to=' + out + '.' + rad_format,
                'scale=0.5',
                'format=' + rad_format], shell=True)
        else:
            subprocess.call([ \
                kraffiti_path + \
                ' from=' + last + '.' + rad_format + \
                ' to=' + out + '.' + rad_format + \
                ' scale=0.5' + \
                ' format=' + rad_format], shell=True)
        generated_files.append(out)

    mip_count += 2

    add_rad_assets(output_file_rad, rad_format, mip_count)

    return mip_count
Ejemplo n.º 10
0
def write_khafilejs(is_play, export_physics, export_navigation, dce_full=False):
    
    sdk_path = armutils.get_sdk_path()
    
    # Merge duplicates and sort
    shader_references = sorted(list(set(assets.shaders)))
    shader_data_references = sorted(list(set(assets.shader_datas)))
    asset_references = sorted(list(set(assets.assets)))
    wrd = bpy.data.worlds['Arm']

    with open('khafile.js', 'w') as f:
        f.write(
"""// Auto-generated
let project = new Project('""" + wrd.arm_project_name + """');

project.addSources('Sources');
""")
        
        f.write(add_armory_library(sdk_path, 'armory'))
        f.write(add_armory_library(sdk_path, 'iron'))
        
        if export_physics:
            f.write("project.addDefine('arm_physics');\n")
            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'
                ammojs_path = ammojs_path.replace('\\', '/')
                f.write("project.addAssets('" + ammojs_path + "');\n")

        if export_navigation:
            f.write("project.addDefine('arm_navigation');\n")
            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'
                recastjs_path = recastjs_path.replace('\\', '/')
                f.write("project.addAssets('" + recastjs_path + "');\n")

        if dce_full:
            f.write("project.addParameter('-dce full');")

        for ref in shader_references:
            f.write("project.addShaders('" + ref + "');\n")
        
        for ref in shader_data_references:
            ref = ref.replace('\\', '/')
            f.write("project.addAssets('" + ref + "');\n")

        for ref in asset_references:
            ref = ref.replace('\\', '/')
            f.write("project.addAssets('" + ref + "');\n")

        if wrd.arm_play_console:
            f.write("project.addDefine('arm_profile');\n")
            f.write(add_armory_library(sdk_path, 'lib/zui'))
            font_path =  sdk_path + '/armory/Assets/droid_sans.ttf'
            font_path = font_path.replace('\\', '/')
            f.write('project.addAssets("' + font_path + '");\n')

        # f.write(add_armory_library(sdk_path, 'lib/haxeui/haxeui-core'))
        # f.write(add_armory_library(sdk_path, 'lib/haxeui/haxeui-kha'))
        # f.write(add_armory_library(sdk_path, 'lib/haxeui/hscript'))

        if wrd.arm_minimize == False:
            f.write("project.addDefine('arm_json');\n")
        
        if wrd.arm_deinterleaved_buffers == True:
            f.write("project.addDefine('arm_deinterleaved');\n")

        if wrd.generate_gpu_skin == False:
            f.write("project.addDefine('arm_cpu_skin');\n")

        for d in assets.khafile_defs:
            f.write("project.addDefine('" + d + "');\n")

        config_text = wrd.arm_khafile
        if config_text != '':
            f.write(bpy.data.texts[config_text].as_string())

        f.write("\n\nresolve(project);\n")
Ejemplo n.º 11
0
def build_node_tree(world):
    output = {}
    dat = {}
    output['material_datas'] = [dat]
    dat['name'] = armutils.safe_filename(world.name) + '_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 = world.name
        world.world_envtex_irr_name = world.name
        write_probes.write_color_irradiance(world.name,
                                            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 = armutils.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'

    # Alternative models
    if wrd.diffuse_model == 'Oren Nayar':
        wrd.world_defs += '_OrenNayar'

    # 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'
        if cam.rp_voxelgi:
            voxelgi = True

    if voxelgi:
        assets.add_khafile_def('arm_voxelgi')
        wrd.world_defs += '_VoxelGI'
        wrd.world_defs += '_Rad'  # Always do radiance for voxels
        wrd.world_defs += '_Irr'

    # 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
Ejemplo n.º 12
0
def parse_color(world, node, context, envmap_strength_const):
    wrd = bpy.data.worlds['Arm']

    # Env map included
    if node.type == 'TEX_ENVIRONMENT' and node.image != None:

        image = node.image
        filepath = image.filepath

        if image.packed_file == None and not os.path.isfile(
                armutils.safe_assetpath(filepath)):
            log.warn(world.name + ' - unable to open ' + image.filepath)
            return

        tex = {}
        context['bind_textures'].append(tex)
        tex['name'] = 'envmap'
        tex['u_addressing'] = 'clamp'
        tex['v_addressing'] = 'clamp'

        # Reference image name
        tex['file'] = armutils.extract_filename(image.filepath)
        tex['file'] = armutils.safe_filename(tex['file'])
        base = tex['file'].rsplit('.', 1)
        ext = base[1].lower()

        if ext == 'hdr':
            target_format = 'HDR'
        else:
            target_format = 'JPEG'
        do_convert = ext != 'hdr' and ext != 'jpg'
        if do_convert:
            if ext == 'exr':
                tex['file'] = base[0] + '.hdr'
                target_format = 'HDR'
            else:
                tex['file'] = base[0] + '.jpg'
                target_format = 'JPEG'

        if image.packed_file != None:
            # Extract packed data
            unpack_path = armutils.get_fp() + '/build/compiled/Assets/unpacked'
            if not os.path.exists(unpack_path):
                os.makedirs(unpack_path)
            unpack_filepath = unpack_path + '/' + tex['file']
            filepath = unpack_filepath

            if do_convert:
                if not os.path.isfile(unpack_filepath):
                    armutils.write_image(image,
                                         unpack_filepath,
                                         file_format=target_format)

            elif os.path.isfile(unpack_filepath) == False or os.path.getsize(
                    unpack_filepath) != image.packed_file.size:
                with open(unpack_filepath, 'wb') as f:
                    f.write(image.packed_file.data)

            assets.add(unpack_filepath)
        else:
            if do_convert:
                converted_path = armutils.get_fp(
                ) + '/build/compiled/Assets/unpacked/' + tex['file']
                filepath = converted_path
                # TODO: delete cache when file changes
                if not os.path.isfile(converted_path):
                    armutils.write_image(image,
                                         converted_path,
                                         file_format=target_format)
                assets.add(converted_path)
            else:
                # Link image path to assets
                assets.add(armutils.safe_assetpath(image.filepath))

        # Generate prefiltered envmaps
        world.world_envtex_name = tex['file']
        world.world_envtex_irr_name = tex['file'].rsplit('.', 1)[0]
        disable_hdr = target_format == 'JPEG'

        mip_count = world.world_envtex_num_mips
        mip_count = write_probes.write_probes(
            filepath,
            disable_hdr,
            mip_count,
            generate_radiance=wrd.generate_radiance)

        world.world_envtex_num_mips = mip_count

        # Append envtex define
        bpy.data.worlds['Arm'].world_defs += '_EnvTex'
        # Append LDR define
        if disable_hdr:
            bpy.data.worlds['Arm'].world_defs += '_EnvLDR'
        # Append radiance define
        if wrd.generate_irradiance and wrd.generate_radiance:
            bpy.data.worlds['Arm'].world_defs += '_Rad'

    # Static image background
    elif node.type == 'TEX_IMAGE':
        bpy.data.worlds['Arm'].world_defs += '_EnvImg'
        tex = {}
        context['bind_textures'].append(tex)
        tex['name'] = 'envmap'
        # No repeat for now
        tex['u_addressing'] = 'clamp'
        tex['v_addressing'] = 'clamp'

        image = node.image
        filepath = image.filepath

        if image.packed_file != None:
            # Extract packed data
            filepath = '/build/compiled/Assets/unpacked'
            unpack_path = armutils.get_fp() + filepath
            if not os.path.exists(unpack_path):
                os.makedirs(unpack_path)
            unpack_filepath = unpack_path + '/' + image.name
            if os.path.isfile(unpack_filepath) == False or os.path.getsize(
                    unpack_filepath) != image.packed_file.size:
                with open(unpack_filepath, 'wb') as f:
                    f.write(image.packed_file.data)
            assets.add(unpack_filepath)
        else:
            # Link image path to assets
            assets.add(armutils.safe_assetpath(image.filepath))

        # Reference image name
        tex['file'] = armutils.extract_filename(image.filepath)
        tex['file'] = armutils.safe_filename(tex['file'])

    # Append sky define
    elif node.type == 'TEX_SKY':
        # Match to cycles
        envmap_strength_const['float'] *= 0.1

        bpy.data.worlds['Arm'].world_defs += '_EnvSky'
        # Append sky properties to material
        const = {}
        const['name'] = 'sunDirection'
        sun_direction = [
            node.sun_direction[0], node.sun_direction[1], node.sun_direction[2]
        ]
        sun_direction[1] *= -1  # Fix Y orientation
        const['vec3'] = list(sun_direction)
        context['bind_constants'].append(const)

        world.world_envtex_sun_direction = sun_direction
        world.world_envtex_turbidity = node.turbidity
        world.world_envtex_ground_albedo = node.ground_albedo

        # Irradiance json file name
        world.world_envtex_irr_name = world.name
        write_probes.write_sky_irradiance(world.name)

        # Radiance
        if wrd.generate_radiance_sky and wrd.generate_radiance and wrd.generate_irradiance:
            bpy.data.worlds['Arm'].world_defs += '_Rad'

            if wrd.generate_radiance_sky_type == 'Hosek':
                hosek_path = 'armory/Assets/hosek/'
            else:
                hosek_path = 'armory/Assets/hosek_fake/'

            sdk_path = armutils.get_sdk_path()
            # Use fake maps for now
            assets.add(sdk_path + hosek_path + 'hosek_radiance.hdr')
            for i in range(0, 8):
                assets.add(sdk_path + hosek_path + 'hosek_radiance_' + str(i) +
                           '.hdr')

            world.world_envtex_name = 'hosek'
            world.world_envtex_num_mips = 8
Ejemplo n.º 13
0
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_input_group(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 None

    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
        pass

    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[0]: # Is Shadow Ray
            return '0.0'
        elif socket == node.outputs[0]: # Is Diffuse Ray
            return '1.0'
        elif socket == node.outputs[0]: # Is Glossy Ray
            return '1.0'
        elif socket == node.outputs[0]: # Is Singular Ray
            return '0.0'
        elif socket == node.outputs[0]: # Is Reflection Ray
            return '0.0'
        elif socket == node.outputs[0]: # Is Transmission Ray
            return '0.0'
        elif socket == node.outputs[0]: # Ray Length
            return '0.0'
        elif socket == node.outputs[0]: # Ray Depth
            return '0.0'
        elif socket == node.outputs[0]: # Transparent Depth
            return '0.0'
        elif socket == node.outputs[0]: # Transmission Depth
            return '0.0'

    elif node.type == 'OBJECT_INFO':
        if socket == node.outputs[0]: # Object Index
            return '0.0'
        elif socket == node.outputs[0]: # Material Index
            return '0.0'
        elif socket == node.outputs[0]: # Random
            return '0.0'

    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 = armutils.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:
            return '0.0'

    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(armutils.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':
        return '0.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'
Ejemplo n.º 14
0
def parse_rgb(node, socket):

    if node.type == 'GROUP':
        return parse_group(node, socket)

    elif node.type == 'GROUP_INPUT':
        return parse_input_group(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 = armutils.safe_source_name(node.name)
        tex = texture.make_texture(node, tex_name)
        if tex != None:
            return '{0}.rgb'.format(texture_store(node, tex, tex_name))
        else:
            return tovec3([0.0, 0.0, 0.0])

    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} + vec3(0.33)), tex_noise({0} * {1} + vec3(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(armutils.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':
#         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])
        out_col = parse_vector_input(node.inputs[4])
#         curshader.add_function(\
# """vec3 hue_sat(const float hue, const float sat, const float val, const float fac, const vec3 col) {
# }
# """)
        return out_col

    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])
Ejemplo n.º 15
0
def patch_project():
    sdk_path = armutils.get_sdk_path()
    fp = armutils.get_fp()
    os.chdir(fp)
    export_data(fp, sdk_path, is_play=True)
Ejemplo n.º 16
0
def build_project(is_play=False, is_publish=False, in_viewport=False, target=None):
    wrd = bpy.data.worlds['Arm']

    # Set target
    if target == None:
        state.target = wrd.arm_project_target.lower()

    # Clear flag
    state.in_viewport = False

    # Save blend
    bpy.ops.wm.save_mainfile()
    log.clear()

    # Set camera in active scene
    active_scene = bpy.context.screen.scene if wrd.arm_play_active_scene else bpy.data.scenes[wrd.arm_project_scene]
    if active_scene.camera == None:
        for o in active_scene.objects:
            if o.type == 'CAMERA':
                active_scene.camera = o
                break

    # Get paths
    sdk_path = armutils.get_sdk_path()
    raw_shaders_path = sdk_path + '/armory/Shaders/'
    
    # Set dir
    fp = armutils.get_fp()
    os.chdir(fp)

    # Create directories
    if not os.path.exists('Sources'):
        os.makedirs('Sources')

    # Compile path tracer shaders
    if len(bpy.data.cameras) > 0 and bpy.data.cameras[0].renderpath_path == 'pathtrace_path':
        path_tracer.compile(raw_shaders_path + 'pt_trace_pass/pt_trace_pass.frag.glsl')

    # Save external scripts edited inside Blender
    write_texts = False
    for text in bpy.data.texts:
        if text.filepath != '' and text.is_dirty:
            write_texts = True
            break
    if write_texts:
        area = bpy.context.area
        old_type = area.type
        area.type = 'TEXT_EDITOR'
        for text in bpy.data.texts:
            if text.filepath != '' and text.is_dirty:
                area.spaces[0].text = text
                bpy.ops.text.save()
        area.type = old_type

    # Save internal Haxe scripts
    for text in bpy.data.texts:
        if text.filepath == '' and text.name[-3:] == '.hx':
            with open('Sources/' + bpy.data.worlds['Arm'].arm_project_package + '/' + text.name, 'w') as f:
                f.write(text.as_string())

    # Export data
    export_data(fp, sdk_path, is_play=is_play, is_publish=is_publish, in_viewport=in_viewport)

    if state.playproc == None:
        log.print_progress(50)
Ejemplo n.º 17
0
def write_probes(image_filepath, disable_hdr, cached_num_mips, generate_radiance=True):
    if not os.path.exists('build/compiled/Assets/envmaps'):
        os.makedirs('build/compiled/Assets/envmaps')

    base_name = image_filepath.rsplit(os.path.sep, 1)[1].rsplit('.', 1)[0] # Extract file name without extension
    
    # Assets to be generated
    output_file_irr = 'build/compiled/Assets/envmaps/' + base_name + '_irradiance'
    if generate_radiance:
        output_file_rad = 'build/compiled/Assets/envmaps/' + base_name + '_radiance'
        rad_format = 'jpg' if disable_hdr else 'hdr'

    # Irradiance exists, keep cache
    if os.path.exists('build/compiled/Assets/envmaps/' + base_name + '_irradiance.arm'):
        add_irr_assets(output_file_irr)
        if generate_radiance:
            add_rad_assets(output_file_rad, rad_format, cached_num_mips)
        return cached_num_mips
    
    # Get paths
    sdk_path = armutils.get_sdk_path()

    if armutils.get_os() == 'win':
        cmft_path = sdk_path + '/armory/tools/cmft/cmft.exe'
        kraffiti_path = sdk_path + '/win32/resources/app/extensions/kha/Kha/Kore/Tools/kraffiti/kraffiti.exe'
    elif armutils.get_os() == 'mac':
        cmft_path = sdk_path + '/armory/tools/cmft/cmft-osx'
        kraffiti_path = sdk_path + '/"Kode Studio.app"/Contents/Resources/app/extensions/kha/Kha/Kore/Tools/kraffiti/kraffiti-osx'
    else:
        cmft_path = sdk_path + '/armory/tools/cmft/cmft-linux64'
        kraffiti_path = sdk_path + '/linux64/resources/app/extensions/kha/Kha/Kore/Tools/kraffiti/kraffiti-linux64'
    
    output_gama_numerator = '1.0' if disable_hdr else '2.2'
    input_file = armutils.safe_assetpath(image_filepath)
    
    # Scale map
    wrd = bpy.data.worlds['Arm']
    target_w = int(wrd.generate_radiance_size)
    target_h = int(target_w / 2)
    scaled_file = output_file_rad + '.' + rad_format

    if armutils.get_os() == 'win':
        output = subprocess.check_output([ \
            kraffiti_path,
            'from=' + input_file,
            'to=' + scaled_file,
            'format=' + rad_format,
            'width=' + str(target_w),
            'height=' + str(target_h)])
    else:
        output = subprocess.check_output([ \
            kraffiti_path + \
            ' from=' + input_file + \
            ' to=' + scaled_file + \
            ' format=' + rad_format + \
            ' width=' + str(target_w) + \
            ' height=' + str(target_h)], shell=True)

    # Generate irradiance
    # gama_options = ''
    # if disable_hdr:
        # gama_options = \
        # ' --inputGammaNumerator 2.2' + \
        # ' --inputGammaDenominator 1.0' + \
        # ' --outputGammaNumerator 1.0' + \
        # ' --outputGammaDenominator ' + output_gama_numerator
    
    # Irradiance spherical harmonics
    if armutils.get_os() == 'win':
        subprocess.call([ \
            cmft_path,
            '--input', scaled_file,
            '--filter', 'shcoeffs',
            #gama_options + \
            '--outputNum', '1',
            '--output0', output_file_irr])
    else:
        subprocess.call([ \
            cmft_path + \
            ' --input ' + scaled_file + \
            ' --filter shcoeffs' + \
            #gama_options + \
            ' --outputNum 1' + \
            ' --output0 ' + output_file_irr], shell=True)

    sh_to_json(output_file_irr)
    add_irr_assets(output_file_irr)
    
    # Mip-mapped radiance
    if generate_radiance == False:
        return cached_num_mips

    # 4096 = 256 face
    # 2048 = 128 face
    # 1024 = 64 face
    face_size = target_w / 8
    if target_w == 2048:
        mip_count = 9
    elif target_w == 1024:
        mip_count = 8
    else:
        mip_count = 7
    
    if armutils.get_os() == 'win':
        subprocess.call([ \
            cmft_path,
            '--input', input_file,
            '--filter radiance',
            '--dstFaceSize', str(face_size),
            '--srcFaceSize', str(face_size),
            '--excludeBase', 'false',
            # '--mipCount', str(mip_count),
            '--glossScale', '7',
            '--glossBias', '3',
            '--lightingModel', 'blinnbrdf',
            '--edgeFixup', 'none',
            '--numCpuProcessingThreads', '4',
            '--useOpenCL', 'true',
            '--clVendor', 'anyGpuVendor',
            '--deviceType', 'gpu',
            '--deviceIndex', '0',
            '--generateMipChain', 'true',
            '--inputGammaNumerator', '2.2',
            '--inputGammaDenominator', '1.0',
            '--outputGammaNumerator', '1.0',
            '--outputGammaDenominator', output_gama_numerator,
            '--outputNum', '1',
            '--output0', output_file_rad,
            '--output0params', 'hdr,rgbe,latlong'])
    else:
        subprocess.call([ \
            cmft_path + \
            ' --input ' + input_file + \
            ' --filter radiance' + \
            ' --dstFaceSize ' + str(face_size) + \
            ' --srcFaceSize ' + str(face_size) + \
            ' --excludeBase false' + \
            #' --mipCount ' + str(mip_count) + \
            ' --glossScale 7' + \
            ' --glossBias 3' + \
            ' --lightingModel blinnbrdf' + \
            ' --edgeFixup none' + \
            ' --numCpuProcessingThreads 4' + \
            ' --useOpenCL true' + \
            ' --clVendor anyGpuVendor' + \
            ' --deviceType gpu' + \
            ' --deviceIndex 0' + \
            ' --generateMipChain true' + \
            ' --inputGammaNumerator 2.2' + \
            ' --inputGammaDenominator 1.0' + \
            ' --outputGammaNumerator 1.0' + \
            ' --outputGammaDenominator ' + output_gama_numerator + \
            ' --outputNum 1' + \
            ' --output0 ' + output_file_rad + \
            ' --output0params hdr,rgbe,latlong'], shell=True)

    # Remove size extensions in file name
    mip_w = int(face_size * 4)
    mip_base = output_file_rad + '_'
    mip_num = 0
    while mip_w >= 4:
        mip_name = mip_base + str(mip_num)
        os.rename(
            mip_name + '_' + str(mip_w) + 'x' + str(int(mip_w / 2)) + '.hdr',
            mip_name + '.hdr')
        mip_w = int(mip_w / 2)
        mip_num += 1

    # Append mips       
    generated_files = []
    for i in range(0, mip_count):
        generated_files.append(output_file_rad + '_' + str(i))
    
    # Convert to jpgs
    if disable_hdr is True:
        for f in generated_files:
            if armutils.get_os() == 'win':
                subprocess.call([ \
                    kraffiti_path,
                    'from=' + f + '.hdr',
                    'to=' + f + '.jpg',
                    'format=jpg'])
            else:
                subprocess.call([ \
                    kraffiti_path + \
                    ' from=' + f + '.hdr' + \
                    ' to=' + f + '.jpg' + \
                    ' format=jpg'], shell=True)
            os.remove(f + '.hdr')
    
    # Scale from (4x2 to 1x1>
    for i in range (0, 2):
        last = generated_files[-1]
        out = output_file_rad + '_' + str(mip_count + i)
        if armutils.get_os() == 'win':
            subprocess.call([ \
                kraffiti_path,
                'from=' + last + '.' + rad_format,
                'to=' + out + '.' + rad_format,
                'scale=0.5',
                'format=' + rad_format], shell=True)
        else:
            subprocess.call([ \
                kraffiti_path + \
                ' from=' + last + '.' + rad_format + \
                ' to=' + out + '.' + rad_format + \
                ' scale=0.5' + \
                ' format=' + rad_format], shell=True)
        generated_files.append(out)
    
    mip_count += 2

    add_rad_assets(output_file_rad, rad_format, mip_count)

    return mip_count
Ejemplo n.º 18
0
def compile_project(target_name=None, is_publish=False, watch=False, patch=False):
    sdk_path =  armutils.get_sdk_path()
    ffmpeg_path = armutils.get_ffmpeg_path()
    wrd = bpy.data.worlds['Arm']

    # Set build command
    if target_name == None:
        target_name = wrd.arm_project_target

    if armutils.get_os() == 'win':
        node_path = sdk_path + '/nodejs/node.exe'
        khamake_path = sdk_path + '/win32/Kha/make'
    elif armutils.get_os() == 'mac':
        node_path = sdk_path + '/nodejs/node-osx'
        khamake_path = sdk_path + '/Kode Studio.app/Contents/Kha/make'
    else:
        node_path = sdk_path + '/nodejs/node-linux64'
        khamake_path = sdk_path + '/linux64/Kha/make'
    
    kha_target_name = make_utils.get_kha_target(target_name)
    cmd = [node_path, khamake_path, kha_target_name]

    if ffmpeg_path != '':
        cmd.append('--ffmpeg')
        cmd.append('"' + ffmpeg_path + '"')

    if armutils.get_os() == 'win': # OpenGL for now
        cmd.append('-g')
        cmd.append('opengl2')

    if kha_target_name == 'krom':
        if state.in_viewport or patch:
            if armutils.glsl_version() >= 330:
                cmd.append('--shaderversion')
                cmd.append('330')
            else:
                cmd.append('--shaderversion')
                cmd.append('110')
        else:
            cmd.append('--to')
            cmd.append('build/window')

    # User defined commands
    cmd_text = wrd.arm_command_line
    if cmd_text != '':
        for s in bpy.data.texts[cmd_text].as_string().split(' '):
            cmd.append(s)

    if state.krom_running:
        if state.compileproc == None: # Already compiling
            # Patch running game, stay silent, disable krafix and haxe
            # cmd.append('--silent')
            cmd.append('--noproject')
            cmd.append('--haxe')
            cmd.append('""')
            cmd.append('--krafix')
            cmd.append('""')
            # Khamake throws error when krafix is not found, hide for now
            state.compileproc = subprocess.Popen(cmd, stderr=subprocess.PIPE)
            threading.Timer(0.1, watch_patch).start()
            return state.compileproc
    elif watch == True:
        state.compileproc = subprocess.Popen(cmd)
        threading.Timer(0.1, watch_compile, ['build']).start()
        return state.compileproc
    else:
        return subprocess.Popen(cmd)
Ejemplo n.º 19
0
def write_khafilejs(is_play, export_physics, export_navigation, dce_full=False):
    
    sdk_path = armutils.get_sdk_path()
    
    # Merge duplicates and sort
    shader_references = sorted(list(set(assets.shaders)))
    shader_data_references = sorted(list(set(assets.shader_datas)))
    asset_references = sorted(list(set(assets.assets)))
    wrd = bpy.data.worlds['Arm']

    with open('khafile.js', 'w') as f:
        f.write(
"""// Auto-generated
let project = new Project('""" + wrd.arm_project_name + """');

project.addSources('Sources');
""")

        # Auto-add assets located in Bundled directory
        if os.path.exists('Bundled'):
            f.write('project.addAssets("Bundled/**");\n')

        if os.path.exists('Libraries/armory'):
            f.write('project.addLibrary("armory")')
        else:
            f.write(add_armory_library(sdk_path, 'armory'))

        if os.path.exists('Libraries/iron'):
            f.write('project.addLibrary("iron")')
        else:
            f.write(add_armory_library(sdk_path, 'iron'))

        # Project libraries
        for lib in wrd.my_librarytraitlist:
            if lib.enabled_prop:
                f.write('project.addLibrary("{0}");\n'.format(lib.name))
        
        if export_physics:
            f.write("project.addDefine('arm_physics');\n")
            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'
                ammojs_path = ammojs_path.replace('\\', '/')
                f.write("project.addAssets('" + ammojs_path + "');\n")

        if export_navigation:
            f.write("project.addDefine('arm_navigation');\n")
            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'
                recastjs_path = recastjs_path.replace('\\', '/')
                f.write("project.addAssets('" + recastjs_path + "');\n")

        if dce_full:
            f.write("project.addParameter('-dce full');")

        for ref in shader_references:
            f.write("project.addShaders('" + ref + "');\n")
        
        for ref in shader_data_references:
            ref = ref.replace('\\', '/')
            f.write("project.addAssets('" + ref + "');\n")

        for ref in asset_references:
            ref = ref.replace('\\', '/')
            f.write("project.addAssets('" + ref + "');\n")

        if wrd.arm_play_console:
            f.write("project.addDefine('arm_profile');\n")

        if wrd.arm_play_console or wrd.arm_ui:
            f.write(add_armory_library(sdk_path, 'lib/zui'))
            p = sdk_path + '/armory/Assets/droid_sans.ttf'
            f.write('project.addAssets("' + p.replace('\\', '/') + '");\n')

        # if wrd.arm_ui:
            # f.write(add_armory_library(sdk_path, 'lib/haxeui-core'))
            # f.write(add_armory_library(sdk_path, 'lib/haxeui-kha'))
            # f.write(add_armory_library(sdk_path, 'lib/hscript'))

        if wrd.arm_minimize == False:
            f.write("project.addDefine('arm_json');\n")
        
        if wrd.arm_deinterleaved_buffers == True:
            f.write("project.addDefine('arm_deinterleaved');\n")

        if wrd.generate_gpu_skin == False:
            f.write("project.addDefine('arm_cpu_skin');\n")

        for d in assets.khafile_defs:
            f.write("project.addDefine('" + d + "');\n")

        config_text = wrd.arm_khafile
        if config_text != '':
            f.write(bpy.data.texts[config_text].as_string())

        f.write("\n\nresolve(project);\n")
Ejemplo n.º 20
0
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[0]:  # Object Index
            return '0.0'
        elif socket == node.outputs[1]:  # Material Index
            return '0.0'
        elif socket == node.outputs[2]:  # Random
            return '0.0'

    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 = armutils.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(armutils.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'
Ejemplo n.º 21
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 = armutils.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(armutils.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':
        #         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])
        out_col = parse_vector_input(node.inputs[4])
        #         curshader.add_function(\
        # """vec3 hue_sat(const float hue, const float sat, const float val, const float fac, const vec3 col) {
        # }
        # """)
        return out_col

    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])
Ejemplo n.º 22
0
Archivo: make.py Proyecto: daela/armory
def build_project(is_play=False, is_publish=False, in_viewport=False, target=None):
    wrd = bpy.data.worlds['Arm']

    # Set target
    if target == None:
        state.target = wrd.arm_project_target.lower()

    # Clear flag
    state.in_viewport = False

    # Save blend
    if armutils.get_save_on_build():
        bpy.ops.wm.save_mainfile()
    
    log.clear()

    # Set camera in active scene
    active_scene = bpy.context.screen.scene if wrd.arm_play_active_scene else bpy.data.scenes[wrd.arm_project_scene]
    if active_scene.camera == None:
        for o in active_scene.objects:
            if o.type == 'CAMERA':
                active_scene.camera = o
                break

    # Get paths
    sdk_path = armutils.get_sdk_path()
    raw_shaders_path = sdk_path + '/armory/Shaders/'
    
    # Set dir
    fp = armutils.get_fp()
    os.chdir(fp)

    # Create directories
    sources_path = 'Sources/' + wrd.arm_project_package
    if not os.path.exists(sources_path):
        os.makedirs(sources_path)

    # Compile path tracer shaders
    if len(bpy.data.cameras) > 0 and bpy.data.cameras[0].renderpath_path == 'pathtrace_path':
        path_tracer.compile(raw_shaders_path + 'pt_trace_pass/pt_trace_pass.frag.glsl')

    # Save external scripts edited inside Blender
    write_texts = False
    for text in bpy.data.texts:
        if text.filepath != '' and text.is_dirty:
            write_texts = True
            break
    if write_texts:
        area = bpy.context.area
        old_type = area.type
        area.type = 'TEXT_EDITOR'
        for text in bpy.data.texts:
            if text.filepath != '' and text.is_dirty and os.path.isfile(text.filepath):
                area.spaces[0].text = text
                bpy.ops.text.save()
        area.type = old_type

    # Save internal Haxe scripts
    for text in bpy.data.texts:
        if text.filepath == '' and text.name[-3:] == '.hx':
            with open('Sources/' + bpy.data.worlds['Arm'].arm_project_package + '/' + text.name, 'w') as f:
                f.write(text.as_string())

    # Export data
    export_data(fp, sdk_path, is_play=is_play, is_publish=is_publish, in_viewport=in_viewport)

    if state.playproc == None:
        log.print_progress(50)