Benedikt Roettger

gorrod

About Me

Connect

LOCATION
Not Specified
WEBSITE

Houdini Skills

Availability

Not Specified

Recent Forum Posts

Alembic and custom attributes July 8, 2023, 12:28 p.m.

I assume writing alembic userproperties would suit your needs? There have already been multiple threads about it on this forum.
e.g.
https://www.sidefx.com/forum/topic/70783/ [www.sidefx.com]

How to divide in COPs April 2, 2023, 4:07 p.m.

You could use a Python COP to generate the average pixel values and write that into a additional plane and then access it with a copinput in another VOP filter, or modify your color values directly in the python COP.
Here is the documentation for it. https://www.sidefx.com/docs/houdini/hom/pythoncop.html [www.sidefx.com]

A caveat on it though, since I was just trying to make this work, is that a COP node seems to cook twice when modifying the C plane that is displayed as the small preview on COP nodes. Once for the actual image, or what is displayed in the composite view with the expected image size, and once more for the small preview image.
The second cook will expect a different amount of pixels/resolution to be set with .setPixelsOfCookingPlane() and will error, which is really annoying.
You can collapse the image preview on cop nodes to avoid this, fix it with a little workaround (e.g. checking the resolution*resolution value against the length of the pixel array and then construct a pixel array with the correct size and sample the it with getPixelByUv() from the original image if that makes sense?) or not write to the C plane directly at all.

This will however only work until you try to write to the C plane in any node further down the stream which then results in another error when cooking the image preview for the python COP.
Maybe someone on the Forum knows how to fix this or do it correctly?

I would maybe suggest doing image operations on points or 2D volumes/heightfields. This would make it a bit easier to work with since the COP2 context seems to be a bit outdated. In the end just sample the volume into COPs when writing it out as an image or do COP specific operations on it.

Anyway here's the example code I put into the python COP to get the average value for each channel in the C plane and write it to the avgC plane which could then be used for further processing in the network. There are plenty of other and better examples in the linked documentation as well:

import numpy as np

def output_planes_to_cook(cop_node):
    # This sample only modifies the color plane.
    #return ("avgC", "C", ) # Uncomment this to see the C plane issue
    return("avgC",)

def required_input_planes(cop_node, output_plane):
    # This sample requires the color and alpha planes from the first input.
    if output_plane in ["avgC", "C"]:
        return ("0", "avgC", "0", "C")
    return ()

def cook(cop_node, plane, resolution):
    input_cop = cop_node.inputs()[0]
    
    color = input_cop.allPixels("C")

    # If writing to the "C" plane this highlights the issue
    if plane=="C" and resolution[0]*resolution[1] != (len(color)/3):
        print("pixel difference: ", len(color)/3, resolution[0]*resolution[1])
        r = color[0:len(color):3]
        r = r[:(resolution[0]*resolution[1])]
        g = color[1:len(color):3]
        r = g[:(resolution[0]*resolution[1])]
        b = color[2:len(color):3]
        r = b[:(resolution[0]*resolution[1])]
    else:
        r = color[0:len(color):3]
        g = color[1:len(color):3]
        b = color[2:len(color):3]
    

    avg_vals = np.array([np.mean(r), np.mean(g), np.mean(b)])
    
    new_r = np.full_like(r, avg_vals[0])
    new_g = np.full_like(r, avg_vals[1])
    new_b = np.full_like(r, avg_vals[2])
    
    cop_node.setPixelsOfCookingPlane(new_r, component="r")
    cop_node.setPixelsOfCookingPlane(new_g, component="g")
    cop_node.setPixelsOfCookingPlane(new_b, component="b")

Digital Asset: display value in parameters ? Oct. 2, 2022, 4:51 a.m.

It works if you set the node path correctly. e.g. detail("/obj/geo1/subnet1/make_rand","rand",0) or probably easier to just set it relative: detail("./make_rand", "rand", 0)