Exemple #1
0
def wrangle_medium(medium):
    """Output a NamedMedium from the input oppath"""
    if not medium:
        return None
    if medium in scene_state.medium_nodes:
        return None
    scene_state.medium_nodes.add(medium)

    medium_vop = BaseNode.from_node(medium)
    if medium_vop is None:
        return None
    if medium_vop.directive != "medium":
        return None

    with api.AttributeBlock():

        coord_sys = medium_vop.coord_sys
        if coord_sys:
            api.Transform(coord_sys)

        colorspace = medium_vop.colorspace
        if colorspace:
            api.ColorSpace(colorspace)

        api.MakeNamedMedium(
            medium_vop.path, medium_vop.directive_type, medium_vop.paramset
        )

    return medium_vop.path
Exemple #2
0
def medium_prim_paramset(prim, paramset=None):
    """Build a ParamSet of medium values based off of hou.Prim attribs"""
    medium_paramset = ParamSet(paramset)

    # NOTE:
    # Testing for prim attribs on each prim is a bit redundat but
    # in general its not an issue as you won't have huge numbers of
    # volumes. If this does become an issue, attribs can be stored in
    # a dict and searched from there. (This includes evaluating the
    # pbrt_interior node.

    # Initialize with the interior shader on the prim, if it exists.
    try:
        interior = prim.stringAttribValue("pbrt_interior")
        interior = BaseNode.from_node(interior)
    except hou.OperationFailed:
        interior = None

    if interior and interior.directive_type == "pbrt_medium":
        medium_paramset |= interior.paramset

    try:
        preset_value = prim.stringAttribValue("preset")
        if preset_value:
            medium_paramset.replace(PBRTParam("string", "preset",
                                              preset_value))
    except hou.OperationFailed:
        pass

    try:
        g_value = prim.floatAttribValue("g")
        medium_paramset.replace(PBRTParam("float", "g", g_value))
    except hou.OperationFailed:
        pass

    try:
        scale_value = prim.floatAttribValue("scale")
        medium_paramset.replace(PBRTParam("float", "scale", scale_value))
    except hou.OperationFailed:
        pass

    try:
        sigma_a_value = prim.floatListAttribValue("sigma_a")
        if len(sigma_a_value) == 3:
            medium_paramset.replace(PBRTParam("rgb", "sigma_a", sigma_a_value))
    except hou.OperationFailed:
        pass

    try:
        sigma_s_value = prim.floatListAttribValue("sigma_s")
        if len(sigma_s_value) == 3:
            medium_paramset.replace(PBRTParam("rgb", "sigma_s", sigma_s_value))
    except hou.OperationFailed:
        pass

    return medium_paramset
Exemple #3
0
def wrangle_preworld_medium(obj, wrangler, now):
    """Output a NamedMedium from the input oppath"""

    # Due to PBRT's scene description we can't use the standard wrangle_medium
    # when declaring a medium and its transform/colorspace when attached to a
    # camera. This is because we don't have AttributeBegin/End blocks to pop
    # the stack, so when we declare the transform for the medium we need to so
    # with respect to being in the camera's coordinate system. We'll extract
    # the translates from the camera, to establish a pivot.
    medium = obj.wrangleString(wrangler, "pbrt_exterior", now, [None])[0]

    if not medium:
        return None
    if medium in scene_state.medium_nodes:
        return None
    scene_state.medium_nodes.add(medium)

    medium_vop = BaseNode.from_node(medium)
    if medium_vop is None:
        return None
    if medium_vop.directive != "medium":
        return None

    coord_sys = medium_vop.coord_sys
    if coord_sys:
        cam_xform = hou.Matrix4(
            get_transform(obj, now, invert=False, flipz=False))
        cam_pivot = cam_xform.extractTranslates()
        cam_pivot = hou.hmath.buildTranslate(cam_pivot).inverted()
        xform = hou.Matrix4(coord_sys)
        xform *= cam_pivot

        api.Transform(xform.asTuple())

    colorspace = medium_vop.colorspace
    if colorspace:
        api.ColorSpace(colorspace)

    api.MakeNamedMedium(medium_vop.path, medium_vop.directive_type,
                        medium_vop.paramset)
    api.Identity()
    # Restore Colorspace if one was set on the Medium
    if colorspace:
        scene_cs = []
        if obj.evalString("pbrt_colorspace", now, scene_cs):
            scene_cs = scene_cs[0]
        else:
            scene_cs = "srgb"
        if scene_cs != colorspace:
            api.ColorSpace(scene_cs)

    return medium_vop.path
def process_full_pt_instance_medium(instance_info, medium_type):
    gdp = instance_info.gdp

    if medium_type not in ("interior", "exterior"):
        return None, None

    medium_attrib_h = gdp.attribute("geo:point", "pbrt_" + medium_type)
    if medium_attrib_h < 0:
        return None, None

    medium = gdp.value(medium_attrib_h, instance_info.number)[0]

    # an empty string is valid here as it means no medium
    if medium == "":
        return medium, ParamSet()

    suffix = ":%s[%i]" % (instance_info.source, instance_info.number)
    medium_node = BaseNode.from_node(medium)
    medium_node.path_suffix = suffix

    if not (medium_node and medium_node.directive_type == "pbrt_medium"):
        return None, None

    medium_paramset = ParamSet(medium_node.paramset)

    # TODO: Currently both this and the geometry overrides
    #       for mediums only support "rgb" and not spectrums.
    parms = {
        "sigma_a": "rgb",
        "sigma_s": "rgb",
        "preset": "string",
        "g": "float",
        "scale": "float",
    }

    for parm, ptype in parms.iteritems():
        attrib_name = "%s_%s" % (medium_type, parm)
        attrib_h = gdp.attribute("geo:point", attrib_name)
        if attrib_h < 0:
            continue
        # TODO: Checks?
        # attrib_size = gdp.attribProperty(attrib_h, "geo:vectorsize")[0]
        # attrib_storage = gdp.attribProperty(attrib_h, "geo:storage")[0]
        val = gdp.value(attrib_h, instance_info.number)
        medium_paramset.replace(PBRTParam(ptype, parm, val))

    # We might be outputing a named medium even if its not going to be needed
    # as in the case of instancing volume prims
    api.MakeNamedMedium(medium_node.full_name, "homogeneous", medium_paramset)

    return medium_node.full_name, medium_paramset
Exemple #5
0
def process_full_pt_instance_medium(instance_info, medium_type):
    gdp = instance_info.gdp

    if medium_type not in ("interior", "exterior"):
        return None, None

    medium_attrib_h = gdp.attribute("geo:point", "pbrt_" + medium_type)
    if medium_attrib_h < 0:
        return None, None

    medium = gdp.value(medium_attrib_h, instance_info.number)[0]

    # an empty string is valid here as it means no medium
    if medium == "":
        return medium, ParamSet()

    suffix = ":%s:%i" % (instance_info.source, instance_info.number)
    medium_node = BaseNode.from_node(medium)
    medium_node.path_suffix = suffix

    if not (medium_node and medium_node.directive == "medium"):
        return None, None

    medium_paramset = ParamSet(medium_node.paramset)

    # Look for attributes to create an override dictionary
    pt_attribs = gdp.globalValue("geo:pointattribs")
    overrides = {}
    for attrib in pt_attribs:
        if not attrib.startswith("{}_".format(medium_type)):
            continue
        if attrib in ("pbrt_interior", "pbrt_exterior"):
            continue
        parm_name = attrib.split("_", 1)[1]
        attrib_h = gdp.attribute("geo:point", attrib)
        if attrib_h < 0:
            continue
        val = gdp.value(attrib_h, instance_info.number)
        overrides[parm_name] = val
    if overrides:
        medium_paramset.update(medium_node.override_paramset(overrides))

    # We might be outputing a named medium even if its not going to be needed
    # as in the case of instancing volume prims
    api.MakeNamedMedium(
        medium_node.full_name, medium_node.directive_type, medium_paramset
    )

    return medium_node.full_name, medium_paramset
def output_medium(medium):
    """Output a NamedMedium from the input oppath"""
    if not medium:
        return None
    if medium in scene_state.medium_nodes:
        return None
    scene_state.medium_nodes.add(medium)

    medium_vop = BaseNode.from_node(medium)
    if medium_vop is None:
        return None
    if medium_vop.directive_type != "pbrt_medium":
        return None

    api.MakeNamedMedium(medium_vop.path, "homogeneous", medium_vop.paramset)
    return medium_vop.path
def wrangle_shading_network(node_path, name_prefix='', saved_nodes=None):
    # Depth first, as textures/materials need to be
    # defined before they are referenced

    # Use this to track if a node has been output or not.
    # if the saved_nodes is None, we use the global scene_state
    # otherwise we use the one passed in. This is useful for outputing
    # named materials within a nested Attribute Block.
    if saved_nodes is None:
        saved_nodes = scene_state.shading_nodes

    prefix_node_path = name_prefix + node_path
    if prefix_node_path in saved_nodes:
        return

    saved_nodes.add(prefix_node_path)

    hnode = hou.node(node_path)

    # Material or Texture?
    node = BaseNode.from_node(hnode)
    if node is None:
        return

    if node.directive == 'material':
        api_call = api.MakeNamedMaterial
    elif node.directive == 'texture':
        api_call = api.Texture
    else:
        return

    for node_input in node.inputs():
        wrangle_shading_network(node_input, name_prefix=name_prefix, saved_nodes=saved_nodes)

    coord_sys = node.coord_sys
    if coord_sys:
        api.TransformBegin()
        api.Transform(coord_sys)
    api_call(name_prefix + node.name,
             node.output_type,
             node.directive_type,
             node.paramset)
    if coord_sys:
        api.TransformEnd()
    if api_call == api.MakeNamedMaterial:
        print()
    return
def wrangle_geo(obj, wrangler, now):

    parm_selection = {
        'object:soppath' : SohoPBRT('object:soppath', 'string', [''], 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'
        # TODO: However this does not seem to apply to shop_materialpaths on the instance points.
        'shop_materialpath' : SohoPBRT('shop_materialpath', 'shaderhandle', skipdefault=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),
        # 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'),
        # We don't use the key=type since its a bit too generic of a name
        'pbrt_curvetype' : SohoPBRT('pbrt_curvetype', 'string', ['flat'], True),
        'pbrt_include' : SohoPBRT('pbrt_include', 'string', [''], False),
        'pbrt_alpha_texture' : SohoPBRT('pbrt_alpha_texture', 'string', [''],
                                         skipdefault=False, key='alpha'),
        'pbrt_shadowalpha_texture' : SohoPBRT('pbrt_shadowalpha_texture', 'string', [''],
                                              skipdefault=False, key='shadowalpha'),
        # TODO, Tesselation options?
    }
    properties = obj.evaluate(parm_selection, now)

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

    if shop and shop in scene_state.shading_nodes:
        api.NamedMaterial(shop)

    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]

    # 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)

    for prop in ('alpha', 'shadowalpha'):
        alpha_tex = properties[prop].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:
                wrangle_shading_network(alpha_node.path, saved_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[prop].Value[0] = ''

    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

    Geo.output_geo(soppath, now, properties)
    return
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
        ),
        "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
        ),
        # 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"
        ),
        # We don't use the key=type since its a bit too generic of a name
        "pbrt_curvetype": SohoPBRT("pbrt_curvetype", "string", ["flat"], True),
        "pbrt_include": SohoPBRT("pbrt_include", "string", [""], False),
        "pbrt_alpha_texture": SohoPBRT(
            "pbrt_alpha_texture", "string", [""], skipdefault=False, key="alpha"
        ),
        "pbrt_shadowalpha_texture": SohoPBRT(
            "pbrt_shadowalpha_texture",
            "string",
            [""],
            skipdefault=False,
            key="shadowalpha",
        ),
        # TODO, Tesselation options?
    }
    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 = Instancing.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)

    for prop in ("alpha", "shadowalpha"):
        alpha_tex = properties[prop].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:
                wrangle_shading_network(alpha_node.path, saved_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[prop].Value[0] = ""

    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

    Geo.output_geo(soppath, now, properties)
    return
def wrangle_shading_network(
    node_path,
    name_prefix="",
    name_suffix="",
    use_named=True,
    saved_nodes=None,
    overrides=None,
    root=True,
):

    if node_path in scene_state.invalid_shading_nodes:
        return

    # Depth first, as textures/materials need to be
    # defined before they are referenced

    # Use this to track if a node has been output or not.
    # if the saved_nodes is None, we use the global scene_state
    # otherwise we use the one passed in. This is useful for outputing
    # named materials within a nested Attribute Block.
    if saved_nodes is None:
        saved_nodes = scene_state.shading_nodes

    # NOTE: We prefix and suffix names here so that there are not collisions when
    #       using full point instancing. There is some possible redundancy as the same
    #       network maybe recreated multiple times under different names if the
    #       overrides are the same. A possible optimization for export and PBRT is to
    #       do a prepass and build the networks before and keep a map to the pre-built
    #       networks. For now we'll brute force it.
    presufed_node_path = name_prefix + node_path + name_suffix
    if presufed_node_path in saved_nodes:
        return

    hnode = hou.node(node_path)

    # Material or Texture?
    node = BaseNode.from_node(hnode)
    if node is None:
        api.Comment("Skipping %s since its not a Material or Texture node" % node_path)
        scene_state.invalid_shading_nodes.add(node_path)
        return
    else:
        saved_nodes.add(presufed_node_path)

    node.path_suffix = name_suffix
    node.path_prefix = name_prefix

    if node.directive == "material":
        api_call = api.MakeNamedMaterial if use_named else api.Material
    elif node.directive == "texture":
        api_call = api.Texture
    else:
        return

    paramset = node.paramset_with_overrides(overrides)

    for node_input in node.inputs():
        wrangle_shading_network(
            node_input,
            name_prefix=name_prefix,
            name_suffix=name_suffix,
            use_named=use_named,
            saved_nodes=saved_nodes,
            overrides=overrides,
            root=False,
        )

    coord_sys = node.coord_sys
    if coord_sys:
        api.TransformBegin()
        api.Transform(coord_sys)

    if api_call == api.Material:
        api_call(node.directive_type, paramset)
    else:
        api_call(node.full_name, node.output_type, node.directive_type, paramset)
    if coord_sys:
        api.TransformEnd()
    if api_call == api.MakeNamedMaterial:
        print()
    return
Exemple #11
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),
        '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),
        # 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'),
        # We don't use the key=type since its a bit too generic of a name
        'pbrt_curvetype':
        SohoPBRT('pbrt_curvetype', 'string', ['flat'], True),
        'pbrt_include':
        SohoPBRT('pbrt_include', 'string', [''], False),
        'pbrt_alpha_texture':
        SohoPBRT('pbrt_alpha_texture',
                 'string', [''],
                 skipdefault=False,
                 key='alpha'),
        'pbrt_shadowalpha_texture':
        SohoPBRT('pbrt_shadowalpha_texture',
                 'string', [''],
                 skipdefault=False,
                 key='shadowalpha'),
        # TODO, Tesselation options?
    }
    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.

    pt_shop_found = False
    if properties['ptinstance'].Value[0] == 1:
        pt_shop_found = Instancing.process_full_pt_instance_material(obj, now)

    # 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)

    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]

    # 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)

    for prop in ('alpha', 'shadowalpha'):
        alpha_tex = properties[prop].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:
                wrangle_shading_network(alpha_node.path, saved_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[prop].Value[0] = ''

    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

    Geo.output_geo(soppath, now, properties)
    return
Exemple #12
0
def wrangle_shading_network(node_path,
                            name_prefix='',
                            name_suffix='',
                            use_named=True,
                            saved_nodes=None,
                            overrides=None):

    # Depth first, as textures/materials need to be
    # defined before they are referenced

    # Use this to track if a node has been output or not.
    # if the saved_nodes is None, we use the global scene_state
    # otherwise we use the one passed in. This is useful for outputing
    # named materials within a nested Attribute Block.
    if saved_nodes is None:
        saved_nodes = scene_state.shading_nodes

    # TODO: Currently (AFAICT) there isn't a case where prefixed and suffixed
    #       names are required. The original intent was to handling instancing
    #       variations, but given that fast instancing doesn't support material
    #       variations it has become moot. The workaround for full instancing is
    #       just to regenerate the shading network each time.
    #       Partitioning based on the different shading overrides might still make
    #       this useful but the current implementation doesn't need this.
    presufed_node_path = name_prefix + node_path + name_suffix
    if presufed_node_path in saved_nodes:
        return

    saved_nodes.add(presufed_node_path)

    hnode = hou.node(node_path)

    # Material or Texture?
    node = BaseNode.from_node(hnode)
    if node is None:
        return

    if node.directive == 'material':
        api_call = api.MakeNamedMaterial if use_named else api.Material
    elif node.directive == 'texture':
        api_call = api.Texture
    else:
        return

    for node_input in node.inputs():
        wrangle_shading_network(node_input,
                                name_prefix=name_prefix,
                                name_suffix=name_suffix,
                                use_named=use_named,
                                saved_nodes=saved_nodes)

    coord_sys = node.coord_sys
    if coord_sys:
        api.TransformBegin()
        api.Transform(coord_sys)

    if api_call == api.Material:
        api_call(node.directive_type, node.paramset)
    else:
        api_call(presufed_node_path, node.output_type, node.directive_type,
                 node.paramset)
    if coord_sys:
        api.TransformEnd()
    if api_call == api.MakeNamedMaterial:
        print()
    return
Exemple #13
0
def smoke_prim_wrangler(prims,
                        paramset=None,
                        properties=None,
                        override_node=None):
    """Outputs a "heterogeneous" Medium and bounding Shape for the input geometry

    The following attributes are checked for via medium_prim_paramset() -
    (See pbrt_medium node for what each parm does)
    pbrt_interior (prim), string
    preset (prim), string
    g (prim), float
    scale (prim), float[3]
    sigma_a (prim), float[3]
    sigma_s (prim), float[3]

    Args:
        prims (list of hou.Prims): Input prims
        paramset (ParamSet): Any base params to add to the shape. (Optional)
        properties (dict): Dictionary of SohoParms (Optional)
    Returns: None
    """
    # NOTE: Overlapping heterogeneous volumes don't currently
    #       appear to be supported, although this may be an issue
    #       with the Medium interface order? Visually it appears one
    #       object is blocking the other.

    # NOTE: Not all samplers support heterogeneous volumes. Determine which
    #       ones do, (and verify this is accurate).
    if properties is None:
        properties = {}

    if "pbrt_ignorevolumes" in properties and properties[
            "pbrt_ignorevolumes"].Value[0]:
        api.Comment("Ignoring volumes because pbrt_ignorevolumes is enabled")
        return

    medium_paramset = ParamSet()
    if "pbrt_interior" in properties:
        interior = BaseNode.from_node(properties["pbrt_interior"].Value[0])
        if interior is not None and interior.directive_type == "pbrt_medium":
            medium_paramset |= interior.paramset
        # These are special overrides that come from full point instancing.
        # It allows "per point" medium values to be "stamped" out to volume prims.
        interior_paramset = properties.get(".interior_overrides")
        if interior_paramset is not None:
            medium_paramset.update(interior_paramset)

    medium_suffix = ""
    instance_info = properties.get(".instance_info")
    if instance_info is not None:
        medium_suffix = ":%s[%i]" % (instance_info.source,
                                     instance_info.number)

    exterior = None
    if "pbrt_exterior" in properties:
        exterior = properties["pbrt_exterior"].Value[0]
    exterior = "" if exterior is None else exterior

    for prim in prims:
        smoke_paramset = ParamSet()

        medium_name = "%s[%i]%s" % (
            properties["object:soppath"].Value[0],
            prim.number(),
            medium_suffix,
        )
        resolution = prim.resolution()
        # TODO: Benchmark this vs other methods like fetching volumeSlices
        voxeldata = array.array("f")
        voxeldata.fromstring(prim.allVoxelsAsString())
        smoke_paramset.add(PBRTParam("integer", "nx", resolution[0]))
        smoke_paramset.add(PBRTParam("integer", "ny", resolution[1]))
        smoke_paramset.add(PBRTParam("integer", "nz", resolution[2]))
        smoke_paramset.add(PBRTParam("point", "p0", [-1, -1, -1]))
        smoke_paramset.add(PBRTParam("point", "p1", [1, 1, 1]))
        smoke_paramset.add(PBRTParam("float", "density", voxeldata))

        medium_prim_overrides = medium_prim_paramset(prim, medium_paramset)
        smoke_paramset.update(medium_prim_overrides)
        smoke_paramset |= paramset

        # By default we'll set a sigma_a and sigma_s to be more Houdini-like
        # however the object's pbrt_interior, or prim's pbrt_interior
        # or prim attribs will override these.
        if (PBRTParam("color", "sigma_a") not in smoke_paramset and PBRTParam(
                "color", "sigma_s") not in smoke_paramset) and PBRTParam(
                    "string", "preset") not in smoke_paramset:
            smoke_paramset.add(PBRTParam("color", "sigma_a", [1, 1, 1]))
            smoke_paramset.add(PBRTParam("color", "sigma_s", [1, 1, 1]))

        with api.AttributeBlock():
            xform = prim_transform(prim)
            api.ConcatTransform(xform)
            api.MakeNamedMedium(medium_name, "heterogeneous", smoke_paramset)
            api.Material("none")
            api.MediumInterface(medium_name, exterior)
            # Pad this slightly?
            bounds_to_api_box([-1, 1, -1, 1, -1, 1])
    return
Exemple #14
0
def smoke_prim_wrangler(prims, paramset=None, properties=None):
    """Outputs a "heterogeneous" Medium and bounding Shape for the input geometry

    The following attributes are checked for via medium_prim_paramset() -
    (See pbrt_medium node for what each parm does)
    pbrt_interior (prim), string
    preset (prim), string
    g (prim), float
    scale (prim), float[3]
    sigma_a (prim), float[3]
    sigma_s (prim), float[3]

    Args:
        prims (list of hou.Prims): Input prims
        paramset (ParamSet): Any base params to add to the shape. (Optional)
        properties (dict): Dictionary of SohoParms (Optional)
    Returns: None
    """
    # NOTE: Overlapping heterogeneous volumes don't currently
    #       appear to be supported, although this may be an issue
    #       with the Medium interface order? Visually it appears one
    #       object is blocking the other.

    # NOTE: Not all samplers support heterogeneous volumes. Determine which
    #       ones do, (and verify this is accurate).
    if properties is None:
        properties = {}

    if ('pbrt_ignorevolumes' in properties
            and properties['pbrt_ignorevolumes'].Value[0]):
        api.Comment('Ignoring volumes because pbrt_ignorevolumes is enabled')
        return

    medium_paramset = ParamSet()
    if 'pbrt_interior' in properties:
        interior = BaseNode.from_node(properties['pbrt_interior'].Value[0])
        if interior is not None and interior.directive_type == 'pbrt_medium':
            medium_paramset |= interior.paramset

    exterior = None
    if 'pbrt_exterior' in properties:
        exterior = properties['pbrt_exterior'].Value[0]
    exterior = '' if exterior is None else exterior

    for prim in prims:
        smoke_paramset = ParamSet()

        name = '%s[%i]' % (properties['object:soppath'].Value[0],
                           prim.number())
        resolution = prim.resolution()
        # TODO: Benchmark this vs other methods like fetching volumeSlices
        voxeldata = array.array('f')
        voxeldata.fromstring(prim.allVoxelsAsString())
        smoke_paramset.add(PBRTParam('integer', 'nx', resolution[0]))
        smoke_paramset.add(PBRTParam('integer', 'ny', resolution[1]))
        smoke_paramset.add(PBRTParam('integer', 'nz', resolution[2]))
        smoke_paramset.add(PBRTParam('point', 'p0', [-1, -1, -1]))
        smoke_paramset.add(PBRTParam('point', 'p1', [1, 1, 1]))
        smoke_paramset.add(PBRTParam('float', 'density', voxeldata))

        medium_prim_overrides = medium_prim_paramset(prim, medium_paramset)
        smoke_paramset.update(medium_prim_overrides)
        smoke_paramset |= paramset

        # By default we'll set a sigma_a and sigma_s to be more Houdini-like
        # however the object's pbrt_interior, or prim's pbrt_interior
        # or prim attribs will override these.
        if ((PBRTParam('color', 'sigma_a') not in smoke_paramset
             and PBRTParam('color', 'sigma_s') not in smoke_paramset)
                and PBRTParam('string', 'preset') not in smoke_paramset):
            smoke_paramset.add(PBRTParam('color', 'sigma_a', [1, 1, 1]))
            smoke_paramset.add(PBRTParam('color', 'sigma_s', [1, 1, 1]))

        with api.AttributeBlock():
            xform = prim_transform(prim)
            api.ConcatTransform(xform)
            api.MakeNamedMedium(name, 'heterogeneous', smoke_paramset)
            api.Material('none')
            api.MediumInterface(name, exterior)
            # Pad this slightly?
            bounds_to_api_box([-1, 1, -1, 1, -1, 1])
    return