05.05.2022, 16:37 fxtd

Camel is a tool for VEX snippets and any other nodes with a custom interface.

It helps format the labels for new parameters if they were written in camel case. Camel also merges parameters into a vector (if they have x, y, etc. characters at the end of the name).

With this tool, you can format the node interface with two clicks: create spare parameters and launch Camel.

Parameters after creation
Parameters after Camel

You can download Camel here and bind it to the shelf, or use the next source code:

import hou
import re

def camel():
    skipTypes = [hou.parmTemplateType.FolderSet,
    hou.parmTemplateType.Folder,
    hou.parmTemplateType.Separator]
    camel = re.compile('^[a-z].*[A-Z]')
    xyzwString = 'xyzw'
    nameXYZW = re.compile('(.+)([{}])'.format(xyzwString))

    for node in hou.selectedNodes():
        templategroup = node.parmTemplateGroup()
        spareTuples = []
        houTuplesXYZW = {}

        for parm in node.spareParms():
            houTuple = parm.tuple()
            template = houTuple.parmTemplate()
            if nameXYZW.match(houTuple.name()) and len(houTuple) == 1 and \
            (template.type() == hou.parmTemplateType.Float or template.type() ==\
                hou.parmTemplateType.Int):
                key = nameXYZW.search(houTuple.name()).groups()[0]
                if key not in houTuplesXYZW:
                    houTuplesXYZW[key] = []
                    houTuplesXYZW[key].append(houTuple)
                elif template.type() == houTuplesXYZW[key][-1].parmTemplate().type() and \
                houTuple not in houTuplesXYZW[key]:
                    houTuplesXYZW[key].append(houTuple)

        for key in houTuplesXYZW.keys():
            houTuplesSolid = []
            charTuplesDict = {}

            for houTuple in houTuplesXYZW[key]:
                char = nameXYZW.search(houTuple.name()).groups()[1]
                charTuplesDict[char] = houTuple

            for char in xyzwString:
                if char in charTuplesDict:
                    houTuplesSolid.append(charTuplesDict[char])
                else:
                    break

            if len(houTuplesSolid) > 1:
                parmsValues = {}

                for houTuple in houTuplesSolid:
                    parm = tuple(houTuple)[0]
                    parmsValues[parm.name()] = parm.eval()

                newTemplate = houTuplesSolid[0].parmTemplate().clone()

                newName = nameXYZW.search(newTemplate.name()).groups()[0]
                newLabel = nameXYZW.search(newTemplate.label()).groups()[0]
                newTemplate.setName(newName)
                newTemplate.setLabel(newLabel)
                newTemplate.setNumComponents(len(houTuplesSolid))
                newTemplate.setNamingScheme(hou.parmNamingScheme.XYZW)

                firstTemplate = houTuplesSolid.pop(0).parmTemplate()
                templategroup.replace(firstTemplate.name(), newTemplate)
                for houTuple in houTuplesSolid:
                    templategroup.remove(houTuple.parmTemplate().name())

                for parmName in parmsValues.keys():
                    node.parm(parmName).set(parmsValues[parmName])

        node.setParmTemplateGroup(templategroup)

        for parm in node.spareParms():
            if parm.tuple() not in spareTuples:
                spareTuples.append(parm.tuple())

        for spareTuple in spareTuples:
            template = spareTuple.parmTemplate()
            if template.type() not in skipTypes:
                name = spareTuple.name()

                if camel.match(name):
                    splittedLabel = re.split(r'([A-Z]+)', name)
                    words = [splittedLabel.pop(0).title()]
                    words += [splittedLabel[n] + splittedLabel[n + 1] for n in \
                    range(0, len(splittedLabel), 2)]
                    template.setLabel(' '.join(words))
                    templategroup.replace(template.name(), template)
                    node.setParmTemplateGroup(templategroup)

20.02.2022, 19:41 fxtd

When using To NDC VOP node in a Volume VOP node, holes may appear in the volume:

This is because some threads are not calculating the VOP correctly. I think the reason of it is the To NDC node was created for shading context, and this may cause an error in the SOP context.

But To NDC node is a greate feature, because it doesn’t have any limits. We can use it for camera clipping, for example. If we do it with VDB, we need to think about the size and the depth of the masking VDB.

There is one method to check how it works. In bad areas z-component of NDC coordinates is the same like in source position P:

The first five records are the result of the erroneous working of the To NDC node

I tried doing it in inside a loop until z-components are the same (with fixed maximum number of steps), but it helped partically. Because sometimes they can be the same. I also tried doing it with SOP-loops, it didn’t help.

So, the only way to solve this problem is disabling multithreading on the Volume VOP node.


26.01.2022, 20:40 fxtd

To hide particles made in addition to an object (for example, smokeobject), you need to create a node Rendering Parameters Volatile:

Next, in the Data Name field, specify Geometry/RenderParms, where Geometry is the name of the data to be hidden.

Then, by changing the Display parameter, you can turn on/off the display of geometry. This doesn’t affect the status of the simulation.


30.09.2021, 00:18 fxtd

Keep in mind that vector in the new volume source should be a merged vdb, or a space separated list of three scalar volumes.


24.09.2021, 17:03 fxtd

This is a live demo showing the result of a custom cloud pipeline.

It shows that you can get fast and high quality results using a combination of standard tools.

Some statistics on one of the projects at the end of the video.


02.11.2020, 16:38 fxtd

It looks like you need to turn off Use Timestep in Volume Source when working with FLIP.
This is tested on 1, 2, 4 and 8 Dopnet Substeps for collisionvel. With the Use Timestep toggle off, the simulation was 100% correct. With it on, the sliding effect appeared.


21.06.2020, 14:22 fxtd

When rendering volumetrics, the scattering phase parameter affects how the object will be shaded: with forward or back scattering.
If scattering phase > 0, then forward scattering occurs. This is typical for water fog.
If scattering phase < 0, then back scattering occurs.  This is typical for smoke.


21.06.2020, 13:59 fxtd

It is advisable to use packed fragments only in cases where either all fragments or most of them are used. A feature of packaged fragments is that “each fragment shares the same geometry, but refers to a subset of it.” Therefore, when deleting individual fragments, there is no memory saving. Even if you delete all the fragments, leaving only one, and write it to disk, then the cache size will be equal to the memory size of the entire model. And when loading the cache, you will still see only one fragment.

In cases where the logic of work involves changing the number of packeds, it is better to use the usual packed geometry. You can create them in a for-each loop with the pack node without breaking them down by name. Also, the copy to points node creates packed geometry.


19.06.2020, 22:47 fxtd

The behavior of an object during bending with a cone twist constraint is strongly influenced by the physical parameter the rotational stiffness. If it is high, then after an impact the object bends worse.


19.06.2020, 11:52 fxtd

It is recommended that you always specify attribute data types: i@class, f@pscale, s@name, and so on. There are a large number of possible errors associated with changing the data type of attributes. And initializing the data type is the first step to avoid these errors.