Beispiel #1
0
def process_full_pt_instance_material(instance_info):

    # The order of evaluation.
    #   1. shaders attached to the actual prims (handled in PBRTgeo.py)
    #   2. per point assignments on the instancer
    #   3. instancer's shop_materialpath
    #   4. object being instanced shop_materialpath
    #   5. nothing
    #   The choice between 3 and 4 is handled automatically by soho

    gdp = instance_info.gdp

    override_attrib_h = gdp.attribute("geo:point", "material_override")
    shop_attrib_h = gdp.attribute("geo:point", "shop_materialpath")

    if shop_attrib_h < 0:
        return False

    shop = gdp.value(shop_attrib_h, instance_info.number)[0]

    override_str = ""
    if override_attrib_h >= 0:
        override_str = gdp.value(override_attrib_h, instance_info.number)[0]

    # We can just reference a NamedMaterial since there are no overrides
    if not override_str:
        if shop in scene_state.shading_nodes:
            api.NamedMaterial(shop)
        else:
            # This shouldn't happen, if it does there is an coding mistake
            raise ValueError("Could not find shop in scene state")
        return True

    overrides = eval(override_str, {}, {})

    # override and shop should exist beyond this point
    # Fully expand shading network since there will be uniqueness
    suffix = ":%s:%i" % (instance_info.source, instance_info.number)
    # NOTE: If this becomes a bottleneck we could potentially cache nodes and params
    # similar to what we do in the PBRTgeo
    wrangle_shading_network(
        shop,
        use_named=False,
        exported_nodes=set(),
        name_suffix=suffix,
        overrides=overrides,
    )
    return True
Beispiel #2
0
def output_materials(obj, wrangler, now, skip_included=False):
    """Output Materials for an object

    The shop_materialpath parameter and shop_materialpath prim attribute
    are both checked for output.
    """
    # We use a shaderhandle instead of a string so Soho instances are properly
    # resolved when Full Instancing is used.
    parms = {
        "shop_materialpath":
        soho.SohoParm("shop_materialpath", "shaderhandle", skipdefault=False),
        "pbrt_include":
        soho.SohoParm("pbrt_include", "string", [""], skipdefault=True),
        "pbrt_import":
        soho.SohoParm("pbrt_import", "string", [""], skipdefault=True),
    }

    eval_parms = obj.evaluate(parms, now)

    if "shop_materialpath" in eval_parms:
        shop = eval_parms["shop_materialpath"].Value[0]
        if shop:
            wrangle_shading_network(shop)

    # If this object uses either an include or import statement then we assume internal
    # material definitions are already resolved through other means.
    if skip_included and ("pbrt_include" in eval_parms
                          or "pbrt_import" in eval_parms):
        return

    soppath = []
    if not obj.evalString("object:soppath", now, soppath):
        return

    soppath = soppath[0]

    gdp = SohoGeometry(soppath, now)
    global_material = gdp.globalValue("shop_materialpath")
    if global_material is not None:
        wrangle_shading_network(global_material[0])

    attrib_h = gdp.attribute("geo:prim", "shop_materialpath")
    if attrib_h >= 0:
        shop_materialpaths = gdp.attribProperty(attrib_h, "geo:allstrings")
        for shop in shop_materialpaths:
            wrangle_shading_network(shop)

    # TODO / CONSIDER, for very large number of instance objects it might speed things
    #   up to cache the fact we've already visited a source network.
    #   Store in scenestate?
    #   (This will avoid much of the below on a per instance basis)
    instance_info = get_full_instance_info(obj, now)
    if instance_info is None:
        return
    attrib_h = instance_info.gdp.attribute("geo:point", "shop_materialpath")
    if attrib_h >= 0:
        shop_materialpaths = instance_info.gdp.attribProperty(
            attrib_h, "geo:allstrings")
        for shop in shop_materialpaths:
            wrangle_shading_network(shop)
    return
Beispiel #3
0
def wrangle_geo(obj, wrangler, now):
    parm_selection = {
        "object:soppath": SohoPBRT("object:soppath", "string", [""], skipdefault=False),
        "ptinstance": SohoPBRT("ptinstance", "integer", [0], skipdefault=False),
        # NOTE: In order for shop_materialpath to evaluate correctly when using
        #       (full) instancing shop_materialpath needs to be a 'shaderhandle'
        #       and not a 'string'
        # NOTE: However this does not seem to apply to shop_materialpaths on the
        #       instance points and has to be done manually
        "shop_materialpath": SohoPBRT(
            "shop_materialpath", "shaderhandle", skipdefault=False
        ),
        "soho_precision": SohoPBRT("soho_precision", "integer", [9], False),
        "pbrt_rendersubd": SohoPBRT("pbrt_rendersubd", "bool", [False], False),
        "pbrt_subdlevels": SohoPBRT(
            "pbrt_subdlevels", "integer", [3], False, key="levels"
        ),
        "pbrt_computeN": SohoPBRT("pbrt_computeN", "bool", [True], False),
        "pbrt_reverseorientation": SohoPBRT(
            "pbrt_reverseorientation", "bool", [False], True
        ),
        "pbrt_matchhoudiniuv": SohoPBRT("pbrt_matchhoudiniuv", "bool", [True], False),
        # The combination of None as a default as well as ignore defaults being False
        # is important. 'None' implying the parm is missing and not available,
        # and '' meaning a vacuum medium.
        # We can't ignore defaults since a default might be the only way to set a
        # medium back to a vacuum.
        "pbrt_interior": SohoPBRT("pbrt_interior", "string", [None], False),
        "pbrt_exterior": SohoPBRT("pbrt_exterior", "string", [None], False),
        "pbrt_ignorevolumes": SohoPBRT("pbrt_ignorevolumes", "bool", [False], True),
        "pbrt_ignorematerials": SohoPBRT("pbrt_ignorematerials", "bool", [False], True),
        "pbrt_splitdepth": SohoPBRT(
            "pbrt_splitdepth", "integer", [3], True, key="splitdepth"
        ),
        "pbrt_emissionfilename": SohoPBRT(
            "pbrt_emissionfilename", "string", [""], True
        ),
        "pbrt_curvetype": SohoPBRT("pbrt_curvetype", "string", ["flat"], True),
        "pbrt_include": SohoPBRT("pbrt_include", "string", [""], False),
        "pbrt_import": SohoPBRT("pbrt_import", "string", [""], False),
        "pbrt_alpha_texture": SohoPBRT(
            "pbrt_alpha_texture", "string", [""], False, key="alpha"
        ),
        "pbrt_allow_geofiles": soho.SohoParm(
            "pbrt_allow_geofiles", "integer", [1], False
        ),
        "pbrt_geo_location": soho.SohoParm(
            "pbrt_geo_location", "string", ["geometry"], False
        ),
        "pbrt_geofile_threshold": soho.SohoParm(
            "pbrt_geofile_threshold", "integer", [10000], False
        ),
        "pbrt_renderpoints": soho.SohoParm("pbrt_renderpoints", "bool", [False], False),
    }
    properties = obj.evaluate(parm_selection, now)

    if "shop_materialpath" not in properties:
        shop = ""
    else:
        shop = properties["shop_materialpath"].Value[0]

    # NOTE: Having to track down shop_materialpaths does not seem to be a requirement
    #       with Mantra or RenderMan. Either its because I'm missing some
    #       logic/initialization either in Soho or in the Shading HDAs. Or there is
    #       some hardcoding in the Houdini libs that know how to translate
    #       shop_materialpath point aassignments to shaders directly through a
    #       SohoParm. Until that is figured out, we'll have to do it manually.

    interior = None
    exterior = None
    if "pbrt_interior" in properties:
        interior = properties["pbrt_interior"].Value[0]
    if "pbrt_exterior" in properties:
        exterior = properties["pbrt_exterior"].Value[0]

    if "pbrt_reverseorientation" in properties:
        if properties["pbrt_reverseorientation"].Value[0]:
            api.ReverseOrientation()

    pt_shop_found = False
    if properties["ptinstance"].Value[0] == 1:
        instance_info = PBRTinstancing.get_full_instance_info(obj, now)
        properties[".instance_info"] = instance_info
        if instance_info is not None:
            pt_shop_found = process_full_pt_instance_material(instance_info)
            interior, interior_paramset = process_full_pt_instance_medium(
                instance_info, "interior"
            )
            exterior, exterior_paramset = process_full_pt_instance_medium(
                instance_info, "exterior"
            )
            if interior_paramset is not None:
                properties[".interior_overrides"] = interior_paramset

    # If we found a point shop, don't output the default one here.
    if shop in scene_state.shading_nodes and not pt_shop_found:
        api.NamedMaterial(shop)

    # We only output a MediumInterface if one or both of the parms exist
    if interior is not None or exterior is not None:
        interior = "" if interior is None else interior
        exterior = "" if exterior is None else exterior
        api.MediumInterface(interior, exterior)

    alpha_tex = properties["alpha"].Value[0]
    alpha_node = BaseNode.from_node(alpha_tex)
    if (
        alpha_node
        and alpha_node.directive == "texture"
        and alpha_node.output_type == "float"
    ):
        if alpha_node.path not in scene_state.shading_nodes:
            suffix = ":%s" % obj.getName()
            alpha_tex = "%s%s" % (alpha_tex, suffix)
            properties["alpha"].Value[0] = alpha_tex
            wrangle_shading_network(
                alpha_node.path, name_suffix=suffix, exported_nodes=set()
            )
    else:
        # If the passed in alpha_texture wasn't valid, clear it so we don't add
        # it to the geometry
        if alpha_tex:
            api.Comment("%s is an invalid float texture" % alpha_tex)
        properties["alpha"].Value[0] = ""

    if properties["pbrt_import"].Value[0]:
        # If we have included a file, skip output any geo.
        api.Import(properties["pbrt_import"].Value[0])
        return

    if properties["pbrt_include"].Value[0]:
        # If we have included a file, skip output any geo.
        api.Include(properties["pbrt_include"].Value[0])
        return

    soppath = properties["object:soppath"].Value[0]
    if not soppath:
        api.Comment("Can not find soppath for object")
        return

    shutter_times = wrangle_motionblur(obj, now)
    if shutter_times is not None:
        times = (shutter_times.open, shutter_times.close)
    else:
        times = (now,)

    if properties["pbrt_renderpoints"].Value[0]:
        PBRTgeo.output_pts(soppath, times, properties)
    else:
        PBRTgeo.output_geo(soppath, now, properties)

    return