Esempio n. 1
0
def create_world_shaders(world: bpy.types.World):
    """Creates fragment and vertex shaders for the given world."""
    global shader_datas
    world_name = arm.utils.safestr(world.name)
    pass_name = 'World_' + world_name

    shader_props = {
        'name': world_name,
        'depth_write': False,
        'compare_mode': 'less',
        'cull_mode': 'clockwise',
        'color_attachments': ['_HDR'],
        'vertex_elements': [{'name': 'pos', 'data': 'float3'}, {'name': 'nor', 'data': 'float3'}]
    }
    shader_data = {'name': world_name + '_data', 'contexts': [shader_props]}

    # ShaderContext expects a material, but using a world also works
    shader_context = ShaderContext(world, shader_data, shader_props)
    vert = shader_context.make_vert(custom_name="World_" + world_name)
    frag = shader_context.make_frag(custom_name="World_" + world_name)

    # Update name, make_vert() and make_frag() above need another name
    # to work
    shader_context.data['name'] = pass_name

    vert.add_out('vec3 normal')
    vert.add_uniform('mat4 SMVP', link="_skydomeMatrix")

    frag.add_include('compiled.inc')
    frag.add_in('vec3 normal')
    frag.add_out('vec4 fragColor')

    frag.write_attrib('vec3 n = normalize(normal);')

    vert.write('''normal = nor;
    vec4 position = SMVP * vec4(pos, 1.0);
    gl_Position = vec4(position);''')

    build_node_tree(world, frag, vert, shader_context)

    # TODO: Rework shader export so that it doesn't depend on materials
    # to prevent workaround code like this
    rel_path = os.path.join(arm.utils.build_dir(), 'compiled', 'Shaders')
    full_path = os.path.join(arm.utils.get_fp(), rel_path)
    if not os.path.exists(full_path):
        os.makedirs(full_path)

    # Output: World_[world_name].[frag/vert].glsl
    make_shader.write_shader(rel_path, shader_context.vert, 'vert', world_name, 'World')
    make_shader.write_shader(rel_path, shader_context.frag, 'frag', world_name, 'World')

    # Write shader data file
    shader_data_file = pass_name + '_data.arm'
    arm.utils.write_arm(os.path.join(full_path, shader_data_file), {'contexts': [shader_context.data]})
    shader_data_path = os.path.join(arm.utils.get_fp_build(), 'compiled', 'Shaders', shader_data_file)
    assets.add_shader_data(shader_data_path)

    assets.add_shader_pass(pass_name)
    assets.shader_passes_assets[pass_name] = shader_context.data
    shader_datas.append({'contexts': [shader_context.data], 'name': pass_name})
Esempio n. 2
0
def write_norpos(con_mesh: shader.ShaderContext,
                 vert: shader.Shader,
                 declare=False,
                 write_nor=True):
    is_bone = con_mesh.is_elem('bone')
    if is_bone:
        make_skin.skin_pos(vert)
    if write_nor:
        prep = 'vec3 ' if declare else ''
        if is_bone:
            make_skin.skin_nor(vert, prep)
        else:
            vert.write_attrib(prep +
                              'wnormal = normalize(N * vec3(nor.xy, pos.w));')
    if con_mesh.is_elem('ipos'):
        make_inst.inst_pos(con_mesh, vert)
Esempio n. 3
0
def write_norpos(con_mesh: ShaderContext,
                 vert: Shader,
                 declare=False,
                 write_nor=True):
    is_bone = con_mesh.is_elem('bone')
    is_morph = con_mesh.is_elem('morph')
    if is_morph:
        make_morph_target.morph_pos(vert)
    if is_bone:
        make_skin.skin_pos(vert)
    if write_nor:
        prep = 'vec3 ' if declare else ''
        if is_morph:
            make_morph_target.morph_nor(vert, is_bone, prep)
        if is_bone:
            make_skin.skin_nor(vert, is_morph, prep)
        if not is_morph and not is_bone:
            vert.write_attrib(prep +
                              'wnormal = normalize(N * vec3(nor.xy, pos.w));')
    if con_mesh.is_elem('ipos'):
        make_inst.inst_pos(con_mesh, vert)
Esempio n. 4
0
def write_tex_coords(con_mesh: ShaderContext, vert: Shader, frag: Shader,
                     tese: Optional[Shader]):
    rpdat = arm.utils.get_rp()

    if con_mesh.is_elem('tex'):
        vert.add_out('vec2 texCoord')
        vert.add_uniform('float texUnpack', link='_texUnpack')
        if mat_state.material.arm_tilesheet_flag:
            if mat_state.material.arm_particle_flag and rpdat.arm_particles == 'On':
                make_particle.write_tilesheet(vert)
            else:
                vert.add_uniform('vec2 tilesheetOffset', '_tilesheetOffset')
                vert.write_attrib(
                    'texCoord = tex * texUnpack + tilesheetOffset;')
        else:
            vert.write_attrib('texCoord = tex * texUnpack;')

        if tese is not None:
            tese.write_pre = True
            make_tess.interpolate(tese,
                                  'texCoord',
                                  2,
                                  declare_out=frag.contains('texCoord'))
            tese.write_pre = False

    if con_mesh.is_elem('tex1'):
        vert.add_out('vec2 texCoord1')
        vert.add_uniform('float texUnpack', link='_texUnpack')
        vert.write_attrib('texCoord1 = tex1 * texUnpack;')
        if tese is not None:
            tese.write_pre = True
            make_tess.interpolate(tese,
                                  'texCoord1',
                                  2,
                                  declare_out=frag.contains('texCoord1'))
            tese.write_pre = False
Esempio n. 5
0
def make(con_mesh: ShaderContext):
    vert = con_mesh.vert
    frag = con_mesh.frag
    geom = con_mesh.geom
    tesc = con_mesh.tesc
    tese = con_mesh.tese

    # Additional values referenced in cycles
    # TODO: enable from cycles.py
    if frag.contains('dotNV') and not frag.contains('float dotNV'):
        frag.write_init('float dotNV = max(dot(n, vVec), 0.0);')

        # n is not always defined yet (in some shadowmap shaders e.g.)
        if not frag.contains('vec3 n'):
            vert.add_out('vec3 wnormal')
            vert.add_uniform('mat3 N', '_normalMatrix')
            vert.write_attrib('wnormal = normalize(N * vec3(nor.xy, pos.w));')
            frag.write_attrib('vec3 n = normalize(wnormal);')

            # If not yet added, add nor vertex data
            vertex_elems = con_mesh.data['vertex_elements']
            has_normals = False
            for elem in vertex_elems:
                if elem['name'] == 'nor':
                    has_normals = True
                    break
            if not has_normals:
                vertex_elems.append({'name': 'nor', 'data': 'short2norm'})

    write_wpos = False
    if frag.contains('vVec') and not frag.contains('vec3 vVec'):
        if tese is not None:
            tese.add_out('vec3 eyeDir')
            tese.add_uniform('vec3 eye', '_cameraPosition')
            tese.write('eyeDir = eye - wposition;')

        else:
            if not vert.contains('wposition'):
                write_wpos = True
            vert.add_out('vec3 eyeDir')
            vert.add_uniform('vec3 eye', '_cameraPosition')
            vert.write('eyeDir = eye - wposition;')
        frag.write_attrib('vec3 vVec = normalize(eyeDir);')

    export_wpos = False
    if frag.contains('wposition') and not frag.contains('vec3 wposition'):
        export_wpos = True
    if tese is not None:
        export_wpos = True
    if vert.contains('wposition'):
        write_wpos = True

    if export_wpos:
        vert.add_uniform('mat4 W', '_worldMatrix')
        vert.add_out('vec3 wposition')
        vert.write_attrib('wposition = vec4(W * spos).xyz;')
    elif write_wpos:
        vert.add_uniform('mat4 W', '_worldMatrix')
        vert.write_attrib('vec3 wposition = vec4(W * spos).xyz;')

    frag_mpos = (
        frag.contains('mposition')
        and not frag.contains('vec3 mposition')) or vert.contains('mposition')
    if frag_mpos:
        vert.add_out('vec3 mposition')
        vert.add_uniform('float posUnpack', link='_posUnpack')
        vert.write_attrib('mposition = spos.xyz * posUnpack;')

    if tese is not None:
        if frag_mpos:
            make_tess.interpolate(tese, 'mposition', 3, declare_out=True)
        elif tese.contains(
                'mposition') and not tese.contains('vec3 mposition'):
            vert.add_out('vec3 mposition')
            vert.write_pre = True
            vert.add_uniform('float posUnpack', link='_posUnpack')
            vert.write('mposition = spos.xyz * posUnpack;')
            vert.write_pre = False
            make_tess.interpolate(tese, 'mposition', 3, declare_out=False)

    frag_bpos = (
        frag.contains('bposition')
        and not frag.contains('vec3 bposition')) or vert.contains('bposition')
    if frag_bpos:
        vert.add_out('vec3 bposition')
        vert.add_uniform('vec3 dim', link='_dim')
        vert.add_uniform('vec3 hdim', link='_halfDim')
        vert.add_uniform('float posUnpack', link='_posUnpack')
        vert.write_attrib('bposition = (spos.xyz * posUnpack + hdim) / dim;')
        vert.write_attrib('if (dim.z == 0) bposition.z = 0;')
        vert.write_attrib('if (dim.y == 0) bposition.y = 0;')
        vert.write_attrib('if (dim.x == 0) bposition.x = 0;')

    if tese is not None:
        if frag_bpos:
            make_tess.interpolate(tese, 'bposition', 3, declare_out=True)
        elif tese.contains(
                'bposition') and not tese.contains('vec3 bposition'):
            vert.add_out('vec3 bposition')
            vert.add_uniform('vec3 dim', link='_dim')
            vert.add_uniform('vec3 hdim', link='_halfDim')
            vert.add_uniform('float posUnpack', link='_posUnpack')
            vert.write_attrib(
                'bposition = (spos.xyz * posUnpack + hdim) / dim;')
            make_tess.interpolate(tese, 'bposition', 3, declare_out=False)

    frag_wtan = (
        frag.contains('wtangent')
        and not frag.contains('vec3 wtangent')) or vert.contains('wtangent')
    if frag_wtan:
        # Indicate we want tang attrib in finalizer to prevent TBN generation
        con_mesh.add_elem('tex', 'short2norm')
        con_mesh.add_elem('tang', 'short4norm')
        vert.add_out('vec3 wtangent')
        vert.write_pre = True
        vert.write('wtangent = normalize(N * tang.xyz);')
        vert.write_pre = False

    if tese is not None:
        if frag_wtan:
            make_tess.interpolate(tese, 'wtangent', 3, declare_out=True)
        elif tese.contains('wtangent') and not tese.contains('vec3 wtangent'):
            vert.add_out('vec3 wtangent')
            vert.write_pre = True
            vert.write('wtangent = normalize(N * tang.xyz);')
            vert.write_pre = False
            make_tess.interpolate(tese, 'wtangent', 3, declare_out=False)

    if frag.contains('vVecCam'):
        vert.add_out('vec3 eyeDirCam')
        vert.add_uniform('mat4 WV', '_worldViewMatrix')
        vert.write('eyeDirCam = vec4(WV * spos).xyz; eyeDirCam.z *= -1;')
        frag.write_attrib('vec3 vVecCam = normalize(eyeDirCam);')

    if frag.contains('nAttr'):
        vert.add_out('vec3 nAttr')
        vert.write_attrib('nAttr = vec3(nor.xy, pos.w);')

    wrd = bpy.data.worlds['Arm']
    if '_Legacy' in wrd.world_defs:
        frag.replace('sampler2DShadow', 'sampler2D')
        frag.replace('samplerCubeShadow', 'samplerCube')