Example #1
0
def mesh_wrangler(gdp, paramset=None, properties=None, override_node=None):
    """Outputs meshes (trianglemesh or loopsubdiv) depending on properties

    If the pbrt_rendersubd property is set and true, a loopsubdiv shape will
    be generated, otherwise a trianglemesh

    Args:
        gdp (hou.Geometry): Input geo
        paramset (ParamSet): Any base params to add to the shape. (Optional)
        properties (dict): Dictionary of SohoParms (Optional)
    Returns: None
    """

    if properties is None:
        properties = {}

    mesh_paramset = ParamSet(paramset)

    # Triangle Meshes in PBRT uses "vertices" to denote positions.
    # These are similar to Houdini "points". Since the PBRT verts
    # are shared between primitives if hard edges or "vertex normals"
    # (Houdini-ese) are required then need to unique the points so
    # so each point can have its own normal.
    # To support this, if any of the triangle mesh params (N, uv, S)
    # are vertex attributes, then we'll uniquify the points.

    # We can only deal with triangles, where Houdini is a bit more
    # general, so we'll need to tesselate

    mesh_gdp = scene_state.tesselate_geo(gdp)
    gdp.clear()

    if not mesh_gdp:
        return None

    # If subdivs are turned on, instead of running the
    # trianglemesh wrangler, use the loop subdiv one instead
    shape = "trianglemesh"
    if "pbrt_rendersubd" in properties:
        if properties["pbrt_rendersubd"].Value[0]:
            shape = "loopsubdiv"

    if shape == "loopsubdiv":
        wrangler_paramset = loopsubdiv_params(mesh_gdp)
        if "levels" in properties:
            wrangler_paramset.replace(properties["levels"].to_pbrt())
    else:
        computeN = True
        if "pbrt_computeN" in properties:
            computeN = properties["pbrt_computeN"].Value[0]
        wrangler_paramset = trianglemesh_params(mesh_gdp, computeN)
        alpha_paramset = mesh_alpha_texs(properties)
        wrangler_paramset.update(alpha_paramset)

    mesh_paramset.update(wrangler_paramset)

    api.Shape(shape, mesh_paramset)

    return None
Example #2
0
def mesh_alpha_texs(properties):
    if not properties:
        return
    paramset = ParamSet()
    for prop in ("alpha", "shadowalpha"):
        if prop not in properties:
            continue
        tex = properties[prop].Value[0]
        if not tex:
            continue
        paramset.add(PBRTParam("texture", prop, tex))
    return paramset
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
def wrangle_film(obj, wrangler, now):

    node = wrangle_node_parm(obj, "film_node", now)
    if node is not None:
        return node.type_and_paramset

    paramset = ParamSet()

    parm_selection = {
        "filename": SohoPBRT("filename", "string", ["pbrt.exr"], False),
        "maxsampleluminance": SohoPBRT("maxsampleluminance", "float", [1e38], True),
        "diagonal": SohoPBRT("diagonal", "float", [35], True),
    }
    parms = obj.evaluate(parm_selection, now)
    for parm_name, parm in parms.iteritems():
        paramset.add(parm.to_pbrt())

    parm_selection = {"res": SohoPBRT("res", "integer", [1280, 720], False)}
    parms = obj.evaluate(parm_selection, now)
    paramset.add(PBRTParam("integer", "xresolution", parms["res"].Value[0]))
    paramset.add(PBRTParam("integer", "yresolution", parms["res"].Value[1]))

    crop_region = obj.getCameraCropWindow(wrangler, now)
    if crop_region != [0.0, 1.0, 0.0, 1.0]:
        paramset.add(PBRTParam("float", "cropwindow", crop_region))

    return ("image", paramset)
Example #5
0
def wrangle_film(obj, wrangler, now):

    node = wrangle_node_parm(obj, 'film_node', now)
    if node is not None:
        return node.type_and_paramset

    paramset = ParamSet()

    parm_selection = {
        'filename' : SohoPBRT('filename', 'string', ['pbrt.exr'], False),
        'maxsampleluminance' : SohoPBRT('maxsampleluminance', 'float', [1e38], True),
        'diagonal' : SohoPBRT('diagonal', 'float', [35], True),
    }
    parms = obj.evaluate(parm_selection, now)
    for parm_name, parm in parms.iteritems():
        paramset.add(parm.to_pbrt())

    parm_selection = {
        'res' : SohoPBRT('res', 'integer', [1280, 720], False),
    }
    parms = obj.evaluate(parm_selection, now)
    paramset.add(PBRTParam('integer', 'xresolution', parms['res'].Value[0]))
    paramset.add(PBRTParam('integer', 'yresolution', parms['res'].Value[1]))

    crop_region = obj.getCameraCropWindow(wrangler, now)
    if crop_region != [0.0, 1.0, 0.0, 1.0]:
        paramset.add(PBRTParam('float', 'cropwindow', crop_region))

    return ('image', paramset)
Example #6
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
Example #7
0
def override_to_paramset(material, override_str):
    """Convert a material override to a ParamSet

    Args:
        material (str): An oppath to a material node
        override_str (str): A string with the overrides (material_override)

    Returns:
        ParamSet of the override params
    """
    paramset = ParamSet()
    override = eval(override_str)
    if not override or not material:
        return paramset
    node = hou.node(material)
    if not node:
        return paramset
    for override_name in override:
        # There can be two style of "overrides" one is a straight parm override
        # which is similar to what Houdini does. The other style of override is
        # for the spectrum type parms. Since spectrum parms can be of different
        # types and the Material Overrides only support "rgb" we are limited
        # in the types of spectrum overrides we can do. To work around this we'll
        # support a different style, override_name:spectrum_type. If the parm name
        # ends in one of the "rgb/color" types then we'll handle it differently.
        try:
            parm_name, spectrum_type = override_name.split(':', 1)
            parm_tuple = node.parmTuple(parm_name)
        except ValueError:
            spectrum_type = None
            parm_name = override_name
            parm = node.parm(parm_name)
            if parm is None:
                continue
            parm_tuple = parm.tuple()

        if spectrum_type is None:
            value = [override[x.name()] for x in parm_tuple]
            pbrt_param = pbrt_param_from_ref(parm_tuple, value)
        elif spectrum_type in ('spectrum', 'xyz', 'blackbody'):
            pbrt_param = PBRTParam(spectrum_type, parm_name,
                                   override[override_name])
        else:
            raise ValueError('Unable to wrangle override name: %s' %
                             override_name)
        paramset.add(pbrt_param)
    return paramset
Example #8
0
def prim_override(prim, override_node):
    paramset = ParamSet()
    if override_node is None:
        return paramset
    override = prim.attribValue("material_override")
    if not override:
        return paramset
    return override_node.override_paramset(override)
Example #9
0
def wrangle_film(obj, wrangler, now):

    node = wrangle_node_parm(obj, "film_node", now)
    if node is not None:
        return node.type_and_paramset

    paramset = ParamSet()

    parm_selection = {
        "filename": SohoPBRT("filename", "string", ["pbrt.exr"], False),
        "maxcomponentvalue": SohoPBRT("maxcomponentvalue", "float", [1e38],
                                      True),
        "diagonal": SohoPBRT("diagonal", "float", [35], True),
        "savefp16": SohoPBRT("savefp16", "bool", [1], True),
    }
    parms = obj.evaluate(parm_selection, now)
    for parm in parms.values():
        paramset.add(parm.to_pbrt())

    parm_selection = {
        "film": SohoPBRT("film", "string", ["rgb"], False),
        "res": SohoPBRT("res", "integer", [1280, 720], False),
    }
    parms = obj.evaluate(parm_selection, now)
    film_name = parms["film"].Value[0]
    paramset.add(PBRTParam("integer", "xresolution", parms["res"].Value[0]))
    paramset.add(PBRTParam("integer", "yresolution", parms["res"].Value[1]))

    crop_region = obj.getCameraCropWindow(wrangler, now)
    if crop_region != [0.0, 1.0, 0.0, 1.0]:
        paramset.add(PBRTParam("float", "cropwindow", crop_region))

    parm_selection = {
        "iso": SohoPBRT("iso", "float", [100], True),
        "whitebalance": SohoPBRT("whitebalance", "float", [0], True),
        "sensor": SohoPBRT("sensor", "string", ["cie1931"], True),
    }

    if film_name == "spectral":
        parm_selection["buckets"] = SohoPBRT("buckets", "integer", [16], True)

    parms = obj.evaluate(parm_selection, now)
    for parm in parms.values():
        paramset.add(parm.to_pbrt())

    return (film_name, paramset)
Example #10
0
def packeddisk_wrangler(gdp,
                        paramset=None,
                        properties=None,
                        override_node=None):
    """Outputs "ply" Shapes for the input geometry

    Args:
        gdp (hou.Geometry): Input geo
        paramset (ParamSet): Any base params to add to the shape. (Optional)
        properties (dict): Dictionary of SohoParms (Optional)
    Returns: None
    """
    alpha_paramset = mesh_alpha_texs(properties)
    for prim in gdp.prims():
        shape_paramset = ParamSet(paramset)
        shape_paramset |= prim_override(prim, override_node)
        filename = prim.intrinsicValue("filename")
        if not filename:
            continue
        if os.path.splitext(filename)[1].lower() != ".ply":
            continue
        shape_paramset.replace(PBRTParam("string", "filename", filename))
        shape_paramset.update(alpha_paramset)
        with api.TransformBlock():
            xform = prim_transform(prim)
            api.ConcatTransform(xform)
            api.Shape("plymesh", shape_paramset)
    return
Example #11
0
def wrangle_accelerator(obj, wrangler, now):

    node = wrangle_node_parm(obj, 'accelerator_node', now)
    if node is not None:
        return node.type_and_paramset

    parm_selection = {
        'accelerator' : SohoPBRT('accelerator', 'string', ['bvh'], False),
    }
    parms = obj.evaluate(parm_selection, now)
    accelerator_name = parms['accelerator'].Value[0]

    if accelerator_name == 'bvh':
        parm_selection = {
            'maxnodeprims' : SohoPBRT('maxnodeprims', 'integer', [4], True),
            'splitmethod' : SohoPBRT('splitmethod', 'string', ['sah'], True),
        }
    else:
        parm_selection = {
            'intersectcost' :
                SohoPBRT('intersectcost', 'integer', [80], True),
            'traversalcostcost' :
                SohoPBRT('traversalcost', 'integer', [1], True),
            'emptybonus' :
                SohoPBRT('emptybonus', 'float', [0.2], True),
            'maxprims' :
                SohoPBRT('maxprims', 'integer', [1], True),
            'kdtree_maxdepth' :
                SohoPBRT('kdtree_maxdepth', 'integer', [1], True,
                         key='maxdepth')
        }
    parms = obj.evaluate(parm_selection, now)

    paramset = ParamSet()

    for parm in parms:
        paramset.add(parms[parm].to_pbrt())

    return (accelerator_name, paramset)
Example #12
0
def wrangle_accelerator(obj, wrangler, now):

    node = wrangle_node_parm(obj, "accelerator_node", now)
    if node is not None:
        return node.type_and_paramset

    parm_selection = {
        "accelerator": SohoPBRT("accelerator", "string", ["bvh"], False)
    }
    parms = obj.evaluate(parm_selection, now)
    accelerator_name = parms["accelerator"].Value[0]

    if accelerator_name == "bvh":
        parm_selection = {
            "maxnodeprims": SohoPBRT("maxnodeprims", "integer", [4], True),
            "splitmethod": SohoPBRT("splitmethod", "string", ["sah"], True),
        }
    else:
        parm_selection = {
            "intersectcost":
            SohoPBRT("intersectcost", "integer", [80], True),
            "traversalcostcost":
            SohoPBRT("traversalcost", "integer", [1], True),
            "emptybonus":
            SohoPBRT("emptybonus", "float", [0.2], True),
            "maxprims":
            SohoPBRT("maxprims", "integer", [1], True),
            "kdtree_maxdepth":
            SohoPBRT("kdtree_maxdepth", "integer", [1], True, key="maxdepth"),
        }
    parms = obj.evaluate(parm_selection, now)

    paramset = ParamSet()

    for parm in parms:
        paramset.add(parms[parm].to_pbrt())

    return (accelerator_name, paramset)
Example #13
0
def wrangle_sampler(obj, wrangler, now):

    node = wrangle_node_parm(obj, "sampler_node", now)
    if node is not None:
        return node.type_and_paramset

    parm_selection = {
        "sampler": SohoPBRT("sampler", "string", ["pmj02bn"], False),
        "pixelsamples": SohoPBRT("pixelsamples", "integer", [16], False),
        "randomization": SohoPBRT("randomization", "string", ["fastowen"], True),
        "jitter": SohoPBRT("jitter", "bool", [1], True),
        "samples": SohoPBRT("samples", "integer", [4, 4], False),
    }
    parms = obj.evaluate(parm_selection, now)

    sampler_name = parms["sampler"].Value[0]
    paramset = ParamSet()

    if sampler_name == "stratified":
        xsamples = parms["samples"].Value[0]
        ysamples = parms["samples"].Value[1]
        paramset.add(PBRTParam("integer", "xsamples", xsamples))
        paramset.add(PBRTParam("integer", "ysamples", ysamples))
        if "jitter" in parms:
            paramset.add(parms["jitter"].to_pbrt())
    else:
        if (
            sampler_name in ("sobol", "paddedsobol", "zsobol", "halton")
            and "randomization" in parms
        ):
            # NOTE: If the halton sampler is picked, it is not compatible with the
            # randomization "fastowen".
            paramset.add(parms["randomization"].to_pbrt())
        paramset.add(parms["pixelsamples"].to_pbrt())

    return (sampler_name, paramset)
Example #14
0
def heightfield_prim_wrangler(prims,
                              paramset=None,
                              properties=None,
                              override_node=None):
    """Outputs a "heightfield" Shapes for the input geometry

    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
    """

    for prim in prims:
        resolution = prim.resolution()
        # If the z resolution is not 1 then this really isn't a heightfield
        if resolution[2] != 1:
            continue

        hf_paramset = ParamSet()

        # Similar to trianglemesh, this is more compact fast, however it might
        # be a memory issue and a generator per voxel or per slice might be a
        # better approach.
        voxeldata = array.array("f")
        voxeldata.fromstring(prim.allVoxelsAsString())

        with api.TransformBlock():

            xform = prim_transform(prim)
            xform = hou.Matrix4(xform)
            srt = xform.explode()
            # Here we need to split up the xform mainly so we can manipulate
            # the scale. In particular Houdini's prim xforms maintain a
            # rotation matrix but the z scale is ignored. So here we are
            # setting it directly to 1 as the "Pz" (or voxeldata) will always
            # be the exact height, no scales are applied to the prim xform.
            # We also need to scale up heightfield since in Houdini by default
            # the size is -1,-1,-1 to 1,1,1 where in pbrt its 0,0,0 to 1,1,1
            api.Translate(*srt["translate"])
            rot = srt["rotate"]
            if rot.z():
                api.Rotate(rot[2], 0, 0, 1)
            if rot.y():
                api.Rotate(rot[1], 0, 1, 0)
            if rot.x():
                api.Rotate(rot[0], 1, 0, 0)
            api.Scale(srt["scale"][0] * 2.0, srt["scale"][1] * 2.0, 1.0)
            api.Translate(-0.5, -0.5, 0)
            hf_paramset.add(PBRTParam("integer", "nu", resolution[0]))
            hf_paramset.add(PBRTParam("integer", "nv", resolution[1]))
            hf_paramset.add(PBRTParam("float", "Pz", voxeldata))
            hf_paramset |= paramset
            hf_paramset |= prim_override(prim, override_node)
            api.Shape("heightfield", hf_paramset)
    return
Example #15
0
def disk_wrangler(gdp, paramset=None, properties=None, override_node=None):
    """Outputs "disk" Shapes for the input geometry

    Args:
        gdp (hou.Geometry): Input geo
        paramset (ParamSet): Any base params to add to the shape. (Optional)
        properties (dict): Dictionary of SohoParms (Optional)
    Returns: None
    """
    # NOTE: PBRT's and Houdini's parameteric UVs are different
    # so when using textures this will need to be fixed on the
    # texture/material side as its not resolvable within Soho.
    for prim in gdp.prims():
        shape_paramset = ParamSet(paramset)
        shape_paramset |= prim_override(prim, override_node)
        with api.TransformBlock():
            xform = prim_transform(prim)
            api.ConcatTransform(xform)
            api.Shape("disk", paramset)
    return
Example #16
0
def sphere_wrangler(gdp, paramset=None, properties=None, override_node=None):
    """Outputs a "sphere" Shapes for the input geometry

    Args:
        gdp (hou.Geometry): Input geo
        paramset (ParamSet): Any base params to add to the shape. (Optional)
        properties (dict): Dictionary of SohoParms (Optional)
    Returns: None
    """
    for prim in gdp.prims():
        shape_paramset = ParamSet(paramset)
        shape_paramset |= prim_override(prim, override_node)
        with api.TransformBlock():
            xform = prim_transform(prim)
            api.ConcatTransform(xform)
            # Scale required to match Houdini's uvs
            api.Scale(1, 1, -1)
            # The inverted z-axis scale means we need to now reverse orientation
            api.ReverseOrientation()
            api.Shape("sphere", shape_paramset)
    return
Example #17
0
def bounds_to_api_box(b):
    """Output a trianglemesh Shape of box based on the input bounds"""

    paramset = ParamSet()
    paramset.add(
        PBRTParam('point', 'P', [
            b[1], b[2], b[5], b[0], b[2], b[5], b[1], b[3], b[5], b[0], b[3],
            b[5], b[0], b[2], b[4], b[1], b[2], b[4], b[0], b[3], b[4], b[1],
            b[3], b[4]
        ]))
    paramset.add(
        PBRTParam('integer', 'indices', [
            0, 3, 1, 0, 2, 3, 4, 7, 5, 4, 6, 7, 6, 2, 7, 6, 3, 2, 5, 1, 4, 5,
            0, 1, 5, 2, 0, 5, 7, 2, 1, 6, 4, 1, 3, 6
        ]))
    api.Shape('trianglemesh', paramset)
Example #18
0
def loopsubdiv_params(mesh_gdp):
    """Generates a ParamSet for a loopsubdiv

    The following attributes are checked for -
    P (point), built-in attribute

    Args:
        mesh_gdp (hou.Geometry): Input geo
    Returns: ParamSet of the attributes on the geometry
    """

    mesh_paramset = ParamSet()

    P = array.array("f")
    P.fromstring(mesh_gdp.pointFloatAttribValuesAsString("P"))

    indices = vtx_attrib_gen(mesh_gdp, None)

    mesh_paramset.add(PBRTParam("integer", "indices", indices))
    mesh_paramset.add(PBRTParam("point", "P", P))

    return mesh_paramset
Example #19
0
def wrangle_light(light, wrangler, now):


    # NOTE: Lights do not support motion blur so we disable it when
    #       outputs the xforms

    node = wrangle_node_parm(light, 'light_node', now)

    parm_selection = {
        'light_wrangler' : SohoPBRT('light_wrangler', 'string', [''], False),
        'light_color' : SohoPBRT('light_color', 'float', [1, 1, 1], False),
        'light_intensity' : SohoPBRT('light_intensity', 'float', [1], False),
        'light_exposure' : SohoPBRT('light_exposure', 'float', [0], False),
    }
    parms = light.evaluate(parm_selection, now)
    light_wrangler = parms['light_wrangler'].Value[0]

    paramset = ParamSet()
    paramset.add(_to_light_scale(parms))

    if light_wrangler == 'HoudiniEnvLight':
        env_map = []
        paramset.add(PBRTParam('rgb', 'L', parms['light_color'].Value))
        if light.evalString('env_map', now, env_map):
            paramset.add(PBRTParam('string', 'mapname', env_map))
        output_xform(light, now, no_motionblur=True)
        api.Scale(1, 1, -1)
        api.Rotate(90, 0, 0, 1)
        api.Rotate(90, 0, 1, 0)
        _light_api_wrapper('infinite', paramset, node)
        return
    elif light_wrangler != 'HoudiniLight':
        api.Comment('This light type, %s, is unsupported' % light_wrangler)
        return

    # We are dealing with a standard HoudiniLight type.

    light_type = light.wrangleString(wrangler, 'light_type', now, ['point'])[0]

    if light_type in ('sphere', 'disk', 'grid', 'tube', 'geo'):

        single_sided = light.wrangleInt(wrangler, 'singlesided', now, [0])[0]
        visible = light.wrangleInt(wrangler, 'light_contribprimary', now, [0])[0]
        size = light.wrangleFloat(wrangler, 'areasize', now, [1, 1])
        paramset.add(PBRTParam('rgb', 'L', parms['light_color'].Value))
        paramset.add(PBRTParam('bool', 'twosided', [not single_sided]))

        # TODO, Possibly get the xform's scale and scale the geo, not the light.
        #       (for example, further multiplying down the radius)
        xform = get_transform(light, now)
        xform_to_api_srt(xform, scale=False)

        _light_api_wrapper('diffuse', paramset, node)

        api.AttributeBegin()

        # PBRT only supports uniform scales for non-mesh area lights
        # this is in part due to explicit light's area scaling factor.
        if light_type in ('grid', 'geo'):
            api.Scale(size[0], size[1], size[0])

        # The visibility only applies to hits on the non-emissive side of the light.
        # the emissive side will still be rendered
        if not visible:
            api.Material('none')

        if light_type == 'sphere':
            # We apply the scale to the radius instead of using a api.Scale
            api.Shape('sphere', [PBRTParam('float', 'radius', 0.5*size[0])])
        elif light_type == 'tube':
            api.Rotate(90, 0, 1, 0)
            api.Shape('cylinder', [PBRTParam('float', 'radius', 0.075*size[1]),
                                   PBRTParam('float', 'zmin', -0.5*size[0]),
                                   PBRTParam('float', 'zmax', 0.5*size[0])])
        elif light_type == 'disk':
            # A bug was introduced with Issue #154 which requires a -z scale
            # on disk area lights
            # See issue #183
            # api.Scale(1,1,-1)
            api.Shape('disk', [PBRTParam('float', 'radius', 0.5*size[0])])
        elif light_type == 'grid':
            api.Shape('trianglemesh', [PBRTParam('integer', 'indices', [0, 3, 1,
                                                                        0, 2, 3]),
                                       PBRTParam('point', 'P', [-0.5, -0.5, 0,
                                                                0.5, -0.5, 0,
                                                                -0.5, 0.5, 0,
                                                                0.5, 0.5, 0])])
        elif light_type == 'geo':
            areageo_parm = hou.node(light.getName()).parm('areageometry')
            if not areageo_parm:
                api.Comment('No "areageometry" parm on light')
                return
            area_geo_node = areageo_parm.evalAsNode()
            if not area_geo_node:
                api.Comment('Skipping, no geometry object specified')
                return
            obj = soho.getObject(area_geo_node.path())
            api.Comment('Light geo from %s' % obj.getName())
            # TODO: The area light scale ('areasize') happens *after* the wrangle_obj's xform
            #       when 'intothisobject' is enabled.
            into_this_obj = light.wrangleInt(wrangler, 'intothisobject', now, [0])[0]
            ignore_xform = not into_this_obj
            wrangle_obj(obj, None, now, ignore_xform=ignore_xform)

        api.AttributeEnd()

        return

    cone_enable = light.wrangleInt(wrangler, 'coneenable', now, [0])[0]
    projmap = light.wrangleString(wrangler, 'projmap', now, [''])[0]
    areamap = light.wrangleString(wrangler, 'areamap', now, [''])[0]

    api_calls = []
    api_calls.append(_apiclosure(output_xform, light, now, no_motionblur=True))
    api_calls.append(_apiclosure(api.Scale, 1, 1, -1))
    api_calls.append(_apiclosure(api.Scale, 1, -1, 1))

    if light_type == 'point':
        paramset.add(PBRTParam('rgb', 'I', parms['light_color'].Value))
        if areamap:
            light_name = 'goniometric'
            paramset.add(PBRTParam('string', 'mapname', [areamap]))
            api_calls = []
            api_calls.append(_apiclosure(output_xform, light, now, no_motionblur=True))
            api_calls.append(_apiclosure(api.Scale, 1, -1, 1))
            api_calls.append(_apiclosure(api.Rotate, 90, 0, 1, 0))
        elif not cone_enable:
            light_name = 'point'
        else:
            conedelta = light.wrangleFloat(wrangler, 'conedelta', now, [10])[0]
            coneangle = light.wrangleFloat(wrangler, 'coneangle', now, [45])[0]
            if projmap:
                light_name = 'projection'
                paramset.add(PBRTParam('float', 'fov', [coneangle]))
                paramset.add(PBRTParam('string', 'mapname', [projmap]))
            else:
                light_name = 'spot'
                coneangle *= 0.5
                coneangle += conedelta
                paramset.add(PBRTParam('float', 'coneangle', [coneangle]))
                paramset.add(PBRTParam('float', 'conedeltaangle', [conedelta]))
    elif light_type == 'distant':
        light_name = light_type
        paramset.add(PBRTParam('rgb', 'L', parms['light_color'].Value))
    else:
        api.Comment('Light Type, %s, not supported' % light_type)
        return

    for api_call in api_calls:
        api_call()
    _light_api_wrapper(light_name, paramset, node)

    return
Example #20
0
def wrangle_camera(obj, wrangler, now):

    node = wrangle_node_parm(obj, 'camera_node', now)
    if node is not None:
        output_cam_xform(obj, node.directive_type, now)
        return node.type_and_paramset

    paramset = ParamSet()

    window = obj.getCameraScreenWindow(wrangler, now)
    parm_selection = {
        'projection' : SohoPBRT('projection', 'string', ['perspective'], False),
        'focal' : SohoPBRT('focal', 'float', [50], False),
        'focalunits' : SohoPBRT('focalunits', 'string', ['mm'], False),
        'aperture' : SohoPBRT('aperture', 'float', [41.4214], False),
        'orthowidth' : SohoPBRT('orthowidth', 'float', [2], False),
        'res' : SohoPBRT('res', 'integer', [1280, 720], False),
        'aspect' : SohoPBRT('aspect', 'float', [1], False),
        'fstop' : SohoPBRT('fstop', 'float', [5.6], False),
        'focaldistance' : SohoPBRT('focus', 'float', [5], False, key='focaldistance'),
        'pbrt_dof' : SohoPBRT('pbrt_dof', 'integer', [0], False),
    }

    parms = obj.evaluate(parm_selection, now)
    aspect = parms['aspect'].Value[0]
    aspectfix = aspect * float(parms['res'].Value[0]) / float(parms['res'].Value[1])

    projection = parms['projection'].Value[0]

    if parms['pbrt_dof'].Value[0]:
        paramset.add(parms['focaldistance'].to_pbrt())
        # to convert from f-stop to lens radius
        # FStop = FocalLength / (Radius * 2)
        # Radius = FocalLength/(FStop * 2)
        focal = parms['focal'].Value[0]
        fstop = parms['fstop'].Value[0]
        units = parms['focalunits'].Value[0]
        focal = soho.houdiniUnitLength(focal, units)
        lens_radius = focal/(fstop*2.0)
        paramset.add(PBRTParam('float', 'lensradius', lens_radius))

    if projection == 'perspective':
        projection_name = 'perspective'

        focal = parms['focal'].Value[0]
        aperture = parms['aperture'].Value[0]
        fov = 2.0 * focal / aperture
        fov = 2.0 * math.degrees(math.atan2(1.0, fov))
        paramset.add(PBRTParam('float', 'fov', [fov]))

        screen = [(window[0] - 0.5) * 2.0,
                  (window[1] - 0.5) * 2.0,
                  (window[2] - 0.5) * 2.0 / aspectfix,
                  (window[3] - 0.5) * 2.0 / aspectfix]
        paramset.add(PBRTParam('float', 'screenwindow', screen))

    elif projection == 'ortho':
        projection_name = 'orthographic'

        width = parms['orthowidth'].Value[0]
        screen = [(window[0] - 0.5) * width,
                  (window[1] - 0.5) * width,
                  (window[2] - 0.5) * width / aspectfix,
                  (window[3] - 0.5) * width / aspectfix]
        paramset.add(PBRTParam('float', 'screenwindow', screen))

    elif projection == 'sphere':
        projection_name = 'environment'
    else:
        soho.error('Camera projection setting of %s not supported by PBRT' %
                   projection)

    output_cam_xform(obj, projection_name, now)

    return (projection_name, paramset)
Example #21
0
def wrangle_integrator(obj, wrangler, now):

    node = wrangle_node_parm(obj, 'integrator_node', now)
    if node is not None:
        return node.type_and_paramset

    parm_selection = {
        'integrator' : SohoPBRT('integrator', 'string', ['path'], False),
        'maxdepth' : SohoPBRT('maxdepth', 'integer', [5], False),
        'rrthreshold' : SohoPBRT('rrthreshold', 'float', [1], True),
        'lightsamplestrategy' :
            SohoPBRT('lightsamplestrategy', 'string', ['spatial'], True),
        'visualizestrategies' :
            SohoPBRT('visualizestrategies', 'toggle', [False], True),
        'visualizeweights' :
            SohoPBRT('visualizeweights', 'toggle', [False], True),
        'iterations' :
            SohoPBRT('iterations', 'integer', [64], True),
        'photonsperiterations' :
            SohoPBRT('photonsperiterations', 'integer', [-1], True),
        'imagewritefrequency' :
            SohoPBRT('imagewritefrequency', 'integer', [2.14748e+09], True),
        'radius' :
            SohoPBRT('radius', 'float', [1], True),
        'bootstrapsamples' :
            SohoPBRT('bootstrapsamples', 'integer', [100000], True),
        'chains' :
            SohoPBRT('chains', 'integer', [1000], True),
        'mutationsperpixel' :
            SohoPBRT('mutataionsperpixel', 'integer', [100], True),
        'largestepprobability' :
            SohoPBRT('largestepprobability', 'float', [0.3], True),
        'sigma' :
            SohoPBRT('sigma', 'float', [0.01], True),
        'strategy' :
            SohoPBRT('strategy', 'string', ['all'], True),
        'nsamples' :
            SohoPBRT('nsamples', 'integer', ['64'], True),
        'cossample' :
            SohoPBRT('cossample', 'toggle', [True], True),
    }

    integrator_parms = {
        'ao' : ['nsamples', 'cossample'],
        'path' : ['maxdepth', 'rrthreshold', 'lightsamplestrategy'],
        'bdpt' : ['maxdepth', 'rrthreshold', 'lightsamplestrategy',
                  'visualizestrategies', 'visualizeweights'],
        'mlt' : ['maxdepth', 'bootstrapsamples', 'chains', 'mutationsperpixel',
                 'largestepprobability', 'sigma'],
        'sppm' : ['maxdepth', 'iterations', 'photonsperiteration',
                  'imagewritefrequency', 'radius'],
        'whitted' : ['maxdepth'],
        'volpath' : ['maxdepth', 'rrthreshold', 'lightsamplestrategy'],
        'directlighting' : ['maxdepth', 'strategy'],
        }
    parms = obj.evaluate(parm_selection, now)

    integrator_name = parms['integrator'].Value[0]
    paramset = ParamSet()
    for parm_name in integrator_parms[integrator_name]:
        if parm_name not in parms:
            continue
        paramset.add(parms[parm_name].to_pbrt())

    return (integrator_name, paramset)
Example #22
0
def wrangle_filter(obj, wrangler, now):

    node = wrangle_node_parm(obj, 'filter_node', now)
    if node is not None:
        return node.type_and_paramset

    parm_selection = {
        'filter' : SohoPBRT('filter', 'string', ['gaussian'], False),
        'filter_width' : SohoPBRT('filter_width', 'float', [2.0, 2.0], False),
        'alpha' : SohoPBRT('gauss_alpha', 'float', [2.0], True, key='alpha'),
        'B' : SohoPBRT('mitchell_B', 'float', [0.333333], True, key='B'),
        'C' : SohoPBRT('mitchell_C', 'float', [0.333333], True, key='C'),
        'tau' : SohoPBRT('sinc_tau', 'float', [3], True, key='tau'),
    }
    parms = obj.evaluate(parm_selection, now)

    filter_name = parms['filter'].Value[0]
    paramset = ParamSet()
    xwidth = parms['filter_width'].Value[0]
    ywidth = parms['filter_width'].Value[1]
    paramset.add(PBRTParam('float', 'xwidth', xwidth))
    paramset.add(PBRTParam('float', 'ywidth', ywidth))

    if filter_name == 'gaussian' and 'alpha' in parms:
        paramset.add(parms['alpha'].to_pbrt())
    if filter_name == 'mitchell' and 'mitchell_B' in parms:
        paramset.add(parms['B'].to_pbrt())
    if filter_name == 'mitchell' and 'mitchell_C' in parms:
        paramset.add(parms['C'].to_pbrt())
    if filter_name == 'sinc' and 'tau' in parms:
        paramset.add(parms['tau'].to_pbrt())
    return (filter_name, paramset)
Example #23
0
def wrangle_light(light, wrangler, now):

    # NOTE: Lights do not support motion blur so we disable it when
    #       outputs the xforms

    node = wrangle_node_parm(light, "light_node", now)

    parm_selection = {
        "light_wrangler": SohoPBRT("light_wrangler", "string", [""], False),
        "light_color": SohoPBRT("light_color", "float", [1, 1, 1], False),
        "light_intensity": SohoPBRT("light_intensity", "float", [1], False),
        "light_exposure": SohoPBRT("light_exposure", "float", [0], False),
    }
    parms = light.evaluate(parm_selection, now)
    light_wrangler = parms["light_wrangler"].Value[0]

    paramset = ParamSet()
    paramset.add(_to_light_scale(parms))

    if light_wrangler == "HoudiniEnvLight":
        env_map = []
        paramset.add(PBRTParam("rgb", "L", parms["light_color"].Value))
        if light.evalString("env_map", now, env_map):
            paramset.add(PBRTParam("string", "mapname", env_map))
        output_xform(light, now, no_motionblur=True)
        api.Scale(1, 1, -1)
        api.Rotate(90, 0, 0, 1)
        api.Rotate(90, 0, 1, 0)
        _light_api_wrapper("infinite", paramset, node)
        return
    elif light_wrangler != "HoudiniLight":
        api.Comment("This light type, %s, is unsupported" % light_wrangler)
        return

    # We are dealing with a standard HoudiniLight type.

    light_type = light.wrangleString(wrangler, "light_type", now, ["point"])[0]

    if light_type in ("sphere", "disk", "grid", "tube", "geo"):

        single_sided = light.wrangleInt(wrangler, "singlesided", now, [0])[0]
        visible = light.wrangleInt(wrangler, "light_contribprimary", now, [0])[0]
        size = light.wrangleFloat(wrangler, "areasize", now, [1, 1])
        paramset.add(PBRTParam("rgb", "L", parms["light_color"].Value))
        paramset.add(PBRTParam("bool", "twosided", [not single_sided]))

        # TODO, Possibly get the xform's scale and scale the geo, not the light.
        #       (for example, further multiplying down the radius)
        xform = get_transform(light, now)
        xform_to_api_srt(xform, scale=False)

        _light_api_wrapper("diffuse", paramset, node)

        api.AttributeBegin()

        # PBRT only supports uniform scales for non-mesh area lights
        # this is in part due to explicit light's area scaling factor.
        if light_type in ("grid", "geo"):
            api.Scale(size[0], size[1], size[0])

        # The visibility only applies to hits on the non-emissive side of the light.
        # the emissive side will still be rendered
        if not visible:
            api.Material("none")

        if light_type == "sphere":
            # We apply the scale to the radius instead of using a api.Scale
            api.Shape("sphere", [PBRTParam("float", "radius", 0.5 * size[0])])
        elif light_type == "tube":
            api.Rotate(90, 0, 1, 0)
            api.Shape(
                "cylinder",
                [
                    PBRTParam("float", "radius", 0.075 * size[1]),
                    PBRTParam("float", "zmin", -0.5 * size[0]),
                    PBRTParam("float", "zmax", 0.5 * size[0]),
                ],
            )
        elif light_type == "disk":
            # After pbrt-v3 commit #2f0852ce api.ReverseOrientation() is needed,
            # prior that it was a api.Scale(1,1,-1)
            # (see issue #183 in pbrt-v3)
            api.ReverseOrientation()
            api.Shape("disk", [PBRTParam("float", "radius", 0.5 * size[0])])
        elif light_type == "grid":
            api.Shape(
                "trianglemesh",
                [
                    PBRTParam("integer", "indices", [0, 3, 1, 0, 2, 3]),
                    PBRTParam(
                        "point",
                        "P",
                        [-0.5, -0.5, 0, 0.5, -0.5, 0, -0.5, 0.5, 0, 0.5, 0.5, 0],
                    ),
                ],
            )
        elif light_type == "geo":
            areageo_parm = hou.node(light.getName()).parm("areageometry")
            if not areageo_parm:
                api.Comment('No "areageometry" parm on light')
                return
            area_geo_node = areageo_parm.evalAsNode()
            if not area_geo_node:
                api.Comment("Skipping, no geometry object specified")
                return
            obj = soho.getObject(area_geo_node.path())
            api.Comment("Light geo from %s" % obj.getName())
            # TODO: The area light scale ('areasize') happens *after* the wrangle_obj's
            #       xform when 'intothisobject' is enabled.
            into_this_obj = light.wrangleInt(wrangler, "intothisobject", now, [0])[0]
            ignore_xform = not into_this_obj
            wrangle_obj(obj, None, now, ignore_xform=ignore_xform)

        api.AttributeEnd()

        return

    cone_enable = light.wrangleInt(wrangler, "coneenable", now, [0])[0]
    projmap = light.wrangleString(wrangler, "projmap", now, [""])[0]
    areamap = light.wrangleString(wrangler, "areamap", now, [""])[0]

    api_calls = []
    api_calls.append(_apiclosure(output_xform, light, now, no_motionblur=True))
    api_calls.append(_apiclosure(api.Scale, 1, 1, -1))
    api_calls.append(_apiclosure(api.Scale, 1, -1, 1))

    if light_type == "point":
        paramset.add(PBRTParam("rgb", "I", parms["light_color"].Value))
        if areamap:
            light_name = "goniometric"
            paramset.add(PBRTParam("string", "mapname", [areamap]))
            api_calls = []
            api_calls.append(_apiclosure(output_xform, light, now, no_motionblur=True))
            api_calls.append(_apiclosure(api.Scale, 1, -1, 1))
            api_calls.append(_apiclosure(api.Rotate, 90, 0, 1, 0))
        elif not cone_enable:
            light_name = "point"
        else:
            conedelta = light.wrangleFloat(wrangler, "conedelta", now, [10])[0]
            coneangle = light.wrangleFloat(wrangler, "coneangle", now, [45])[0]
            if projmap:
                light_name = "projection"
                paramset.add(PBRTParam("float", "fov", [coneangle]))
                paramset.add(PBRTParam("string", "mapname", [projmap]))
            else:
                light_name = "spot"
                coneangle *= 0.5
                coneangle += conedelta
                paramset.add(PBRTParam("float", "coneangle", [coneangle]))
                paramset.add(PBRTParam("float", "conedeltaangle", [conedelta]))
    elif light_type == "distant":
        light_name = light_type
        paramset.add(PBRTParam("rgb", "L", parms["light_color"].Value))
    else:
        api.Comment("Light Type, %s, not supported" % light_type)
        return

    for api_call in api_calls:
        api_call()
    _light_api_wrapper(light_name, paramset, node)

    return
Example #24
0
def wrangle_camera(obj, wrangler, now):

    node = wrangle_node_parm(obj, "camera_node", now)
    if node is not None:
        output_cam_xform(obj, node.directive_type, now)
        return node.type_and_paramset

    paramset = ParamSet()

    window = obj.getCameraScreenWindow(wrangler, now)
    parm_selection = {
        "projection": SohoPBRT("projection", "string", ["perspective"], False),
        "focal": SohoPBRT("focal", "float", [50], False),
        "focalunits": SohoPBRT("focalunits", "string", ["mm"], False),
        "aperture": SohoPBRT("aperture", "float", [41.4214], False),
        "orthowidth": SohoPBRT("orthowidth", "float", [2], False),
        "res": SohoPBRT("res", "integer", [1280, 720], False),
        "aspect": SohoPBRT("aspect", "float", [1], False),
        "fstop": SohoPBRT("fstop", "float", [5.6], False),
        "focaldistance": SohoPBRT("focus", "float", [5], False, key="focaldistance"),
        "pbrt_dof": SohoPBRT("pbrt_dof", "integer", [0], False),
    }

    parms = obj.evaluate(parm_selection, now)
    aspect = parms["aspect"].Value[0]
    aspectfix = aspect * float(parms["res"].Value[0]) / float(parms["res"].Value[1])

    projection = parms["projection"].Value[0]

    if parms["pbrt_dof"].Value[0]:
        paramset.add(parms["focaldistance"].to_pbrt())
        # to convert from f-stop to lens radius
        # FStop = FocalLength / (Radius * 2)
        # Radius = FocalLength/(FStop * 2)
        focal = parms["focal"].Value[0]
        fstop = parms["fstop"].Value[0]
        units = parms["focalunits"].Value[0]
        focal = soho.houdiniUnitLength(focal, units)
        lens_radius = focal / (fstop * 2.0)
        paramset.add(PBRTParam("float", "lensradius", lens_radius))

    if projection == "perspective":
        projection_name = "perspective"

        focal = parms["focal"].Value[0]
        aperture = parms["aperture"].Value[0]
        fov = 2.0 * focal / aperture
        fov = 2.0 * math.degrees(math.atan2(1.0, fov))
        paramset.add(PBRTParam("float", "fov", [fov]))

        screen = [
            (window[0] - 0.5) * 2.0,
            (window[1] - 0.5) * 2.0,
            (window[2] - 0.5) * 2.0 / aspectfix,
            (window[3] - 0.5) * 2.0 / aspectfix,
        ]
        paramset.add(PBRTParam("float", "screenwindow", screen))

    elif projection == "ortho":
        projection_name = "orthographic"

        width = parms["orthowidth"].Value[0]
        screen = [
            (window[0] - 0.5) * width,
            (window[1] - 0.5) * width,
            (window[2] - 0.5) * width / aspectfix,
            (window[3] - 0.5) * width / aspectfix,
        ]
        paramset.add(PBRTParam("float", "screenwindow", screen))

    elif projection == "sphere":
        projection_name = "environment"
    else:
        soho.error("Camera projection setting of %s not supported by PBRT" % projection)

    output_cam_xform(obj, projection_name, now)

    return (projection_name, paramset)
Example #25
0
def wrangle_integrator(obj, wrangler, now):

    node = wrangle_node_parm(obj, "integrator_node", now)
    if node is not None:
        return node.type_and_paramset

    parm_selection = {
        "integrator": SohoPBRT("integrator", "string", ["path"], False),
        "maxdepth": SohoPBRT("maxdepth", "integer", [5], False),
        "rrthreshold": SohoPBRT("rrthreshold", "float", [1], True),
        "lightsamplestrategy": SohoPBRT(
            "lightsamplestrategy", "string", ["spatial"], True
        ),
        "visualizestrategies": SohoPBRT("visualizestrategies", "toggle", [False], True),
        "visualizeweights": SohoPBRT("visualizeweights", "toggle", [False], True),
        "iterations": SohoPBRT("iterations", "integer", [64], True),
        "photonsperiterations": SohoPBRT("photonsperiterations", "integer", [-1], True),
        "imagewritefrequency": SohoPBRT(
            "imagewritefrequency", "integer", [2.14748e09], True
        ),
        "radius": SohoPBRT("radius", "float", [1], True),
        "bootstrapsamples": SohoPBRT("bootstrapsamples", "integer", [100000], True),
        "chains": SohoPBRT("chains", "integer", [1000], True),
        "mutationsperpixel": SohoPBRT("mutataionsperpixel", "integer", [100], True),
        "largestepprobability": SohoPBRT("largestepprobability", "float", [0.3], True),
        "sigma": SohoPBRT("sigma", "float", [0.01], True),
        "strategy": SohoPBRT("strategy", "string", ["all"], True),
        "nsamples": SohoPBRT("nsamples", "integer", ["64"], True),
        "cossample": SohoPBRT("cossample", "toggle", [True], True),
    }

    integrator_parms = {
        "ao": ["nsamples", "cossample"],
        "path": ["maxdepth", "rrthreshold", "lightsamplestrategy"],
        "bdpt": [
            "maxdepth",
            "rrthreshold",
            "lightsamplestrategy",
            "visualizestrategies",
            "visualizeweights",
        ],
        "mlt": [
            "maxdepth",
            "bootstrapsamples",
            "chains",
            "mutationsperpixel",
            "largestepprobability",
            "sigma",
        ],
        "sppm": [
            "maxdepth",
            "iterations",
            "photonsperiteration",
            "imagewritefrequency",
            "radius",
        ],
        "whitted": ["maxdepth"],
        "volpath": ["maxdepth", "rrthreshold", "lightsamplestrategy"],
        "directlighting": ["maxdepth", "strategy"],
    }
    parms = obj.evaluate(parm_selection, now)

    integrator_name = parms["integrator"].Value[0]
    paramset = ParamSet()
    for parm_name in integrator_parms[integrator_name]:
        if parm_name not in parms:
            continue
        paramset.add(parms[parm_name].to_pbrt())

    return (integrator_name, paramset)
Example #26
0
def wrangle_filter(obj, wrangler, now):

    node = wrangle_node_parm(obj, "filter_node", now)
    if node is not None:
        return node.type_and_paramset

    parm_selection = {
        "filter": SohoPBRT("filter", "string", ["gaussian"], False),
        "filter_width": SohoPBRT("filter_width", "float", [2.0, 2.0], False),
        "alpha": SohoPBRT("gauss_alpha", "float", [2.0], True, key="alpha"),
        "B": SohoPBRT("mitchell_B", "float", [0.333333], True, key="B"),
        "C": SohoPBRT("mitchell_C", "float", [0.333333], True, key="C"),
        "tau": SohoPBRT("sinc_tau", "float", [3], True, key="tau"),
    }
    parms = obj.evaluate(parm_selection, now)

    filter_name = parms["filter"].Value[0]
    paramset = ParamSet()
    xwidth = parms["filter_width"].Value[0]
    ywidth = parms["filter_width"].Value[1]
    paramset.add(PBRTParam("float", "xwidth", xwidth))
    paramset.add(PBRTParam("float", "ywidth", ywidth))

    if filter_name == "gaussian" and "alpha" in parms:
        paramset.add(parms["alpha"].to_pbrt())
    if filter_name == "mitchell" and "B" in parms:
        paramset.add(parms["B"].to_pbrt())
    if filter_name == "mitchell" and "C" in parms:
        paramset.add(parms["C"].to_pbrt())
    if filter_name == "sinc" and "tau" in parms:
        paramset.add(parms["tau"].to_pbrt())
    return (filter_name, paramset)
Example #27
0
def curve_wrangler(gdp, paramset=None, properties=None, override_node=None):
    """Outputs a "curve" Shape for input geometry

    The following attributes are checked for -

    P (point), built-in attribute
    width (vertex/point/prim), float
    N (vertex/point), float[3]
    curvetype (prim), string (overrides the property pbrt_curvetype)

    Args:
        gdp (hou.Geometry): Input geo
        paramset (ParamSet): Any base params to add to the shape. (Optional)
        properties (dict): Dictionary of SohoParms (Optional)
    Returns: None
    """

    if properties is None:
        properties = {}

    shape_paramset = ParamSet(paramset)

    curve_type = None
    if "pbrt_curvetype" in properties:
        curve_type = properties["pbrt_curvetype"].Value[0]
        shape_paramset.add(PBRTParam("string", "type", curve_type))
    if "splitdepth" in properties:
        shape_paramset.add(properties["splitdepth"].to_pbrt())

    gdp = _convert_nurbs_to_bezier(gdp)

    has_vtx_width = False if gdp.findVertexAttrib("width") is None else True
    has_pt_width = False if gdp.findPointAttrib("width") is None else True
    has_prim_width = False if gdp.findPrimAttrib("width") is None else True
    has_prim_width01 = False
    if (gdp.findPrimAttrib("width0") is not None
            and gdp.findPrimAttrib("width1") is not None):
        has_prim_width01 = True

    has_curvetype = False if gdp.findPrimAttrib("curvetype") is None else True

    has_vtx_N = False if gdp.findVertexAttrib("N") is None else True
    has_pt_N = False if gdp.findPointAttrib("N") is None else True

    for prim in gdp.prims():

        curve_paramset = ParamSet()
        prim_curve_type = curve_type

        # Closed curve surfaces are not supported
        if prim.intrinsicValue("closed"):
            continue

        order = prim.intrinsicValue("order")
        degree = order - 1
        # PBRT only supports degree 2 or 3 curves
        # TODO: We could possibly convert the curves to a format that
        #       pbrt supports but for now we'll expect the user to have
        #       a curve basis which is supported
        # https://www.codeproject.com/Articles/996281/NURBS-crve-made-easy
        if degree not in (2, 3):
            continue
        curve_paramset.add(PBRTParam("integer", "degree", degree))

        if prim.intrinsicValue("typename") == "BezierCurve":
            basis = "bezier"
        else:
            # We should not see these as they are being converted to BezierCurves
            basis = "bspline"
        curve_paramset.add(PBRTParam("string", "basis", [basis]))

        # SPEED consideration, run inline:
        # P = prim_pt2vtx_attrib_gen(prim)
        P = [pt.attribValue("P") for pt in prim.points()]
        curve_paramset.add(PBRTParam("point", "P", P))

        if has_curvetype:
            prim_val = prim.attribValue("curvetype")
            prim_curve_type = prim_val if prim_val else curve_type

        if prim_curve_type is not None:
            curve_paramset.add(PBRTParam("string", "type", [prim_curve_type]))

        if prim_curve_type == "ribbon":

            if has_vtx_N or has_pt_N:
                N = (prim.attribValueAt("N", u)
                     for u in prim.intrinsicValue("knots"))
            else:
                # If ribbon, normals must exist
                # TODO: Let pbrt error? Or put default values?
                N = [(0, 0, 1)] * len(prim.intrinsicValue("knots"))

            if N is not None:
                curve_paramset.add(PBRTParam("normal", "N", N))

        if has_vtx_width:
            curve_paramset.add(
                PBRTParam("float", "width0",
                          prim.vertex(0).attribValue("width")))
            curve_paramset.add(
                PBRTParam("float", "width1",
                          prim.vertex(-1).attribValue("width")))
        elif has_pt_width:
            curve_paramset.add(
                PBRTParam("float", "width0",
                          prim.vertex(0).point().attribValue("width")))
            curve_paramset.add(
                PBRTParam("float", "width1",
                          prim.vertex(-1).point().attribValue("width")))
        elif has_prim_width01:
            curve_paramset.add(
                PBRTParam("float", "width0", prim.attribValue("width0")))
            curve_paramset.add(
                PBRTParam("float", "width1", prim.attribValue("width1")))
        elif has_prim_width:
            curve_paramset.add(
                PBRTParam("float", "width", prim.attribValue("width")))
        else:
            # Houdini's default matches a width of 0.05
            curve_paramset.add(PBRTParam("float", "width", 0.05))

        curve_paramset |= shape_paramset
        curve_paramset |= prim_override(prim, override_node)
        api.Shape("curve", curve_paramset)
    return
Example #28
0
def nurbs_wrangler(gdp, paramset=None, properties=None, override_node=None):
    """Outputs a "nurbs" Shape for input geometry

    The following attributes are checked for -
    P (point), built-in attribute

    Args:
        gdp (hou.Geometry): Input geo
        paramset (ParamSet): Any base params to add to the shape. (Optional)
        properties (dict): Dictionary of SohoParms (Optional)
    Returns: None
    """

    # TODO: - Figure out how the Pw attribute works in Houdini
    # has_Pw = False if gdp.findPointAttrib('Pw') is None else True
    has_Pw = False

    # TODO   - Figure out how to query [uv]_extent in hou
    # u_extent_h = gdp.attribute('geo:prim', 'geo:ubasisextent')
    # v_extent_h = gdp.attribute('geo:prim', 'geo:vbasisextent')

    for prim in gdp.prims():

        nurbs_paramset = ParamSet()

        row = prim.intrinsicValue("nu")
        col = prim.intrinsicValue("nv")
        u_order = prim.intrinsicValue("uorder")
        v_order = prim.intrinsicValue("vorder")
        u_wrap = prim.intrinsicValue("uwrap")
        v_wrap = prim.intrinsicValue("vwrap")
        u_knots = prim.intrinsicValue("uknots")
        v_knots = prim.intrinsicValue("vknots")

        if u_wrap:
            row += u_order - 1
        if v_wrap:
            col += v_order - 1
        nurbs_paramset.add(PBRTParam("integer", "nu", row))
        nurbs_paramset.add(PBRTParam("integer", "nv", col))
        nurbs_paramset.add(PBRTParam("integer", "uorder", u_order))
        nurbs_paramset.add(PBRTParam("integer", "vorder", v_order))
        nurbs_paramset.add(PBRTParam("float", "uknots", u_knots))
        nurbs_paramset.add(PBRTParam("float", "vknots", v_knots))
        # NOTE: Currently not sure how these are set within Houdini
        #       but they are queryable
        #       The Platonic SOP, Teapot -> Convert to NURBS can make these.
        # nurbs_paramset.add(PBRTParam('float', 'u0', u_extent[0]))
        # nurbs_paramset.add(PBRTParam('float', 'v0', v_extent[0]))
        # nurbs_paramset.add(PBRTParam('float', 'u1', u_extent[1]))
        # nurbs_paramset.add(PBRTParam('float', 'v1', v_extent[1]))

        # if row + u_order != len(u_knots):
        #    api.Comment('Invalid U')
        # if col + v_order != len(v_knots):
        #    api.Comment('Invalid V')

        P = []
        for v in xrange(col):
            for u in xrange(row):
                vtx = prim.vertex(u % prim.numCols(), v % prim.numRows())
                pt = vtx.point()
                P.append(pt.attribValue("P"))
        if not has_Pw:
            nurbs_paramset.add(PBRTParam("point", "P", P))
        else:
            # TODO: While the pbrt scene file looks right, the render
            #       is a bit odd. Scaled up geo? Not what I was expecting.
            #       Perhaps compare to RMan.
            w = prim_pt2vtx_attrib_gen(prim, "Pw")
            Pw = itertools.izip(P, w)
            nurbs_paramset.add(PBRTParam("float", "Pw", Pw))

        nurbs_paramset |= paramset
        nurbs_paramset |= prim_override(prim, override_node)
        api.Shape("nurbs", nurbs_paramset)
Example #29
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
Example #30
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