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.


19.12.2021, 19:12 fxtd

This is a simple python script to change file paths in selected Read and Write nodes. You can select part of the Nuke script, and if the selected nodes have a “file” knob, it will be changed:

replace_from = 'short'
replace_to = 'medium'

for node in nuke.selectedNodes():
    if node.knob('file'):
        node['file'].setValue(node['file'].value().replace(replace_from, replace_to))


19.12.2021, 14:36 fxtd

SyncToy 2.1 is no longer available for download from the Mircosoft website. But it still works great on Windows 10 and is used in many cases of work automation. You can download the latest release of SyncToy 2.1 here.


24.10.2021, 19:02 fxtd

If you are a freelancer or work in a small studio, you may not have an automatic cleanup and backup system for projects. This greatly affects the free space on the storage. And cleaning up previous projects takes a long time when you don’t have enough space for the current project.

The best way to avoid this is to have a specific project structure and use a backup process. During this process, unnecessary data such as geometry caches that can be recovered from scenes and unnecessary data versions are automatically deleted according to the project structure and some specific rules.

If you don’t follow this way, cleaning up the project will be a very slow process because, literally, you have to check all the project files manually.

If you use a more or less correct data storage process, you will have many versions of the file sequences at the end of the project. They usually take up most of the space that can be cleaned up before backing up. In this case, we can clean up the project in a semi-automatic mode.

If you have many folders with version numbers in their names (e.g. v001, v002, v01, v02, etc.), this Python script will help you. It shows folders containing multiple versions. You just need to run the script from the command line:

python c:\showVersions.py M:\PROJECT

where M:\PROJECT is the root of the project you want to start cleaning up from.

You can also use additional arguments, for example:

python c:\showVersions.py M:\PROJECT render 2 5.5GB

where render is an optional keyword. It is used to filter the paths of the found folders. For example, you can search for versions only in the render folder, or you can search for versions in the folders of a specific artist: in this case, you need to use his name as a keyword. 2 – the minimum allowed number of versions, for example, if you want the found folders to contain more than 2 versions. 5.5GB is the minimum size of versions found. If you don’t want to search for small size versions, you can use this filter. GB in this argument are required characters, you can use a different spelling of the number: 0.001GB, 10GB, .5GB, etc.

Additional arguments can be used optionally and in any order.

The result of the script is as follows:

python C:\showVersions.py M:\LAST_PROJECT render 3 20.5GB

M:\LAST_PROJECT\SHOTS\SCENE02\SCENE02_0030\render\flood
Versions size: 31.92 GB
v001
v002
v003
v004

M:\LAST_PROJECT\SHOTS\SCENE04\SCENE04_0020\render\water
Versions size: 89.27 GB
v001
v002
v003
v004
v005

M:\LAST_PROJECT\SHOTS\SCENE03\SCENE03_0040\render\destruction
Versions size: 32.74 GB
v001
v003
v004
v005

M:\LAST_PROJECT\SHOTS\SCENE03\SCENE03_0060\render\base
Versions size: 22.81 GB
v001
v002
v003
v004
v005

Press Enter to continue...

Now we can check the displayed paths and remove unnecessary versions, for example, all but the last one. I always do it manually because I have a rule: never delete files with a script.


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.


30.09.2021, 00:12 fxtd

First of all, SyncToy is a great tool for data synchronization. You can use it with Task Sheduler for backups, downloads from remote render farms, synchronization between work and home, etc.

SyncToy can be used in shell mode in the background. It can also be used for manual synchronization.

There is a manual preview mode where you can select the files you want to sync. This mode has one huge drawback: you can’t select multiple items in the preview window, just select, unselect, and toggle all selections:

Preview window

In the image above, you can’t use the scroll or shift keys, for example, to select and run just a new operation. But Python can.

A very simple Python script can help us. If you don’t have Python on your computer, you can download it there: for example, Python 3.9.7. After the installation is complete, we need to install one additional library with the command from the command line:

С:\Python39\scripts\pip install pynput

where С:\Python39\ is the location of your installed Python.

Then place the following Python script in the Python folder – C:\Python39\ – just for ease of running. Name it select.py (you can download it here and unzip it to that folder):

import time
import sys
import pynput
from pynput.keyboard import Key, Controller
keyboard = Controller()

time.sleep(5)

for i in range(0, int(sys.argv[1])):
    keyboard.press(' ')
    time.sleep(0.1)
    keyboard.press(Key.down)
    time.sleep(0.1)

Select the first required item in the preview window and check how many files you need to select:

Select the first required item

Then just run the python script from the command line:

cd C:\Python39
python select.py 986

where С:\Python39\ is also the location of your installed Python, 986 is the number of files to check.

You now have only 5 seconds to activate the preview window. After a minute or two, the selection will be complete:

Selection result

And you can run syncing:

Synchronization result

All the previous steps are very fast and Python installation is pretty simple.

The Python script above only simulates pressing the spacebar and down arrow a selected number of times.

Enjoy!


24.09.2021, 23:38 fxtd

Hey! Sometimes I make useful RNDs. The core of most of them is Python. But not always. Nevertheless, I started a new category – Scripts.

The results of my interesting RNDs will be posted here. I hope someday they’ll help someone as well as they helped me.

Also you can look at Python tag from Database. Scripts from any category can be found by this tag.


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.