Jump to content

Dynamiczne dodawanie VOPów z poziomu SHOPa?


jamnique

Recommended Posts

Pytanie do forumowych masterów: Czy da się dynamicznie dodawać VOPy do shadera z poziomu parameter editora w SHOPach? Jakimiś script buttonami?

 

Chcę stworzyć sobie wersję Mantra Shadera, gdzie do każdego parametru można dynamicznie dodać jeden lub kilka noisów i / lub tekstur i mieszać je ze sobą. Użytkownik klika sobie na plusik i dodaje warstwę, którą może później usunąć. Dodatkowo chciałbym również móc dodawać ad hoc nowe lub wybierać już istniejące UV dla każdej z warstw z osobna...

Link to comment
Share on other sites

  • Replies 10
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Hej,

sorry za późną odpowiedź. Nie wiem, czy już uporałeś się, ale technicznie jest to oczywiście możliwe, chociaż nie wiem, na ile ma to sens. Mam wrażenie, że to, o co pytasz się wybitnie niepraktyczne dla większych shaderów. Taka funkcjonalność jest na poziomie VOPów pod MMB na inputach btw.

 

Jak stworzysz dowolny materiał w SHOPie, możesz dodać do jego parametrów na przykład OrderedMenu. Potem ustawiasz dla niego callback script. Komplikacją jest, że dopóki Twój materiał nie jest zapisany w HDA, tego skryptu nie zapiszesz na nodzie, ale przypuszczam, że shader i tak będziesz chciał zapisać w HDA.

 

Callback może zrobić wszystko co chcesz, dodawać tekstury etc, tyle tylko, że im bardziej skomplikowany setup, tym trudniej będzie to ogarnąć skryptem... Załączam przykład. Callback jest zapisany w hou.session, więc razem z hipem. Materiał nie jest w hda.

 

pozdrawiam,

skk.

 

ps Ordered menu jest obok parametru diffuse na /shop/vopmaterial1

shop_menus_example.hip.zip

Link to comment
Share on other sites

Dzięki SYmek. Myślę że z tym co mi wysłałeś dam radę zrobić to co chciałem.

 

Chodzi mi o to, żeby móc kilkoma klikami dodać do dowolnego parametru detal high i low frequency. W tej chwili tylko dla displacementu przewidziano możliwość dodania tekstury i / lub noisa z poziomu paramater editora, a jest to (moim zdaniem) bardzo wygodne rozwiązanie.

 

Chciałbym móc dodawać sloty na tekstury / noisy dynamicznie, żeby nie zaśmiecać interfejsu i shadera, a dać użytkownikowi możliwość dodania tylu warstw ile potrzebuje. Np dwa poziomy noisa (high + low) + dwie tekstury, każda z innym tilingiem.

 

W XSI przy każdym parametrze materiału była ikonka która skrywała dropdown menu. Można było z niego wybierać tekstury proceduralne, image, weight mapy, gradienty itd. Po dokonaniu wyboru do każdej z tych tekstur można było w locie dodać i edytować nowe UV. Pozwalało to bardzo szybko narzucić na obiekt kilka teksturek, albo nawet tą samą kilka razy z różnym mapowaniem i uzyskać jakiś efekt. O ile mnie pamięć nie myli, wszystkie te zmiany były automatycznie odzwierciedlane w node editorze, więc można było później już tam pracować. Innymi słowy działało to tak jakby edytowanie interfejsu w parameter editorze automatycznie tworzyło odpowiednie VOPy.

 

Wiem że to może się wydawać bez sensu - nie po to ma się nodowy edytor materiałów, żeby próbować robić oldskulowy material editor w stylu 3ds Maxa w parameter editorze. Jednak chodzi o szybkość i wygodę przy takich prostych, codziennych materiałach.

 

Alternatywnym rozwiązaniem byłoby uporządkowanie bebechów Mantra Shadera tak, żeby łatwo było do niego dopinać nody. W tej chwili wszystko jest tam na wierzchu na jednym poziomie hierarchii i ma kilometrowe wąsy, przez co grzebanie w środku jest niezbyt wygodne.

Link to comment
Share on other sites

Hej,

nie chciałem Cię zniechęcać, tylko zaznaczyć nadchodzące kłopoty :). Wiem, że to może być wygodne! Po to właśnie dodali MMB na Vopach, które mogą dodawać tekstry, noisy etc (menu jest edytowalne i możesz dodawać własne rzeczy). Także shelfy działają w ten sposób, ale też pokazują ograniczenia techniki. Kilka uwag:

 

- zdaje się, że obowiązujący paradygmat (który oczywiście możesz mieć głęboko) jest taki, że nadmiar parametrów się ukrywa. Po to dodali niedawno warunek hidden when dla parametrów.

- kłopot zaczyna się przy wielokrotnym użyciu parametru, bo jak raz ustawisz noise, potem texture a potem znów noise, to drugi noise musi działać nieco inaczej, co dla programowania jest niedobre etc. Nic, czego nie da się ogarnąć, tylko kod się komplikuje. Trochę jak w przypadku shelfa, 4 pierwsze kliknięcia działają, potem już nie :). Usuwanie starych rzeczy, kontrolowanie, co do czego jest obecnie podpięte...

- rozważyłbym zrobienie własnego noda, która ma w sobie zaszyte elementy i logikę i który sam może się poszerzać (dodawać warstwy), masz wtedy kontrolę nad tym, co dzieje się w środku. A na zewnątrz tylko vector.

 

To są luźne myśli w oparciu o własne doświadczenia. Swoją drogą może jest to teraz przyjemniejsze, bo HOM dla Vopów jest nieco lepszy (dodali setNamedInput(), kiedyś trzeba było szukać inputów po indeksach).

 

Powodzenia!

skk.

Link to comment
Share on other sites

Dzięki, nie zniechęciłeś mnie :) Raczej zachęciłeś żeby się zainteresować callbackami.

 

A możesz zdradzić jak pracujecie z materiałami u siebie? Macie swój własny monolityczny shader, który jest przyjaźniejszy, albo zmodyfikowaną wersję Mantra Shadera? A może jedziecie na principled shader, albo w ogóle nie używacie Mantry?

Link to comment
Share on other sites

A możesz zdradzić jak pracujecie z materiałami u siebie? Macie swój własny monolityczny shader, który jest przyjaźniejszy, albo zmodyfikowaną wersję Mantra Shadera?

 

A wiesz, że teraz to nie wiem :). To się zmienia. Mieliśmy kiedyś własny shader rozwijany w kodzie. Potem własny Vop jak podstawa, z którego robiło się shader. Teraz zdaje się jedziemy na standardzie, który w miarę potrzeb jest modyfikowany (plus swoje Vopy) i zapisywany do HDA dla każdego obiektu. U nas lead robi materiały, ludzie świecą i renderują. Jak trzeba coś zmienić, albo proszą leada, albo sami robią swój materiał.

 

 

A może jedziecie na principled shader, albo w ogóle nie używacie Mantry?

 

Principled shader chyba najmniej..., ale Mantra renderuje 99.9% naszych klatek niezmiennie od 8 lat :)

Link to comment
Share on other sites

Dzięki za odpowiedź. Jeśli mogę przy okazji spytać o jeszcze jedną rzecz ...

 

Korzystam z Image Plane'ów opartych na własnych atrybutach do maskowania obiektów. Czyli nadaję atrybut danemu obiektowi w sopach, a później przez Mantra Shader sprawdzam czy jego wartość to 1 czy 0 i na tej podstawie genetuję matte.

 

Czy dałoby się tak zmodyfikować Mantra Shader (albo Mantra ROP), żeby sam czytał z obiektu wszystkie atrybuty według podanego klucza (np po nazwie Mask_*), i robił z nich image plany? Czy może jest jakiś o wiele sprytniejszy sposób robienia tego, którym mógłbys się podzielić?

Link to comment
Share on other sites

Dzięki za odpowiedź. Jeśli mogę przy okazji spytać o jeszcze jedną rzecz ...

 

Korzystam z Image Plane'ów opartych na własnych atrybutach do maskowania obiektów. Czyli nadaję atrybut danemu obiektowi w sopach, a później przez Mantra Shader sprawdzam czy jego wartość to 1 czy 0 i na tej podstawie genetuję matte.

 

Czy dałoby się tak zmodyfikować Mantra Shader (albo Mantra ROP), żeby sam czytał z obiektu wszystkie atrybuty według podanego klucza (np po nazwie Mask_*), i robił z nich image plany? Czy może jest jakiś o wiele sprytniejszy sposób robienia tego, którym mógłbys się podzielić?

 

Się porobiło... przez lata nikt sobie matte'ami głowy nie zawracał, ale teraz to jest gorący temat :)

 

Nie ma dobrego sposobu na masowe produkowanie masek... Niby wszystko proste a w praktyce zawsze coś... Oczywiście możesz sobie na wiele sposobów ułatwić sprawę, poskryptować, ale naprawdę dobre rozwiązania są dopiero w drodze, jako że zrobiła się ostatnio moda na auto-matte'y różnych maści. Sam mam swój projekt, PsyOp opublikował właśnie swoją metodą, Dreamworks ma swoją i jeszcze kilku innych. Generalnie wszystkie te patenty sprowadzają się do tego, żeby nie spłaszczać w pixelfiltrze sampli opacity, tylko przenieść je rozdzielone do kompozytora i w ten sposób umożliwić generowanie masek on-demad :). Chyba stary dobry rpf(?) tak robił, kto by pomyślał, że MAX był taki postępowy... no, ale to przyszłość.

 

Shader nie może dodawać plane'ów, może tylko eksportować zmienne, a i tak te muszą być zdefiniowane w parametrach funkcji shadera, co wybitnie utrudnia skryptowanie eksportów, muszą tam być od początku expressis verbis. Można by się pobawać macrami w VEX, tak jak jest to zrobione w eksportach w illuminance loop per światło, ale nie próbowałem tego choćby dlatego, że trzeba by podmienić wbudowane VOPy, albo edytować voplib.h, co jest mało production friendly... można to chyba ogarnąć łatwiej.

 

Najprostsza metoda to zrobić sktypt, który przejrzy wszystkie shadery na obiektach i stworzy plane'y dla eksportów, ale jak sam zauważyłeś, jest to mało inteligentne. Nieco bardziej zaawansowana metoda polega na filtrowaniu IFD'ka Pythonem. Nie możesz wprawdzie dodawać image plane'ów, ale możesz je stworzyć wcześniej w dużej ilości i wyłączyć. Potem robisz callback w Pythonie, który kolekcjonuje shadery. Callback zwraca Ci shader string, czyli nazwę shadera ze wszystkimi parametrami, które nie mają wartości domyślnych. Czyli masz shader bunny_mat i na nim parametr mask=1 (a domyślnie 0), więc callback zwróci Ci /shop/bunny_mat diff 0.6 0.3 0.1 mask 1. Mając te informacje, możesz włączyć jeden plane i ustawić mu potrzebne dane.

 

Jeśli renderujesz własnym skryptem (polecam), możesz edytować scenę w trakcie generowania IFD tak, że grafik nigdy nie zobaczy tego bajzlu, który generujesz :). Czyli:

 

1) dodajesz plane'y do Mantra ROP przed generowaniem IFD

2) filtrujesz IFD Pythonem czytając z shaderów szczegóły potrzebne dla masek.

 

W takim przypadku w ogóle nie musisz ustawiać nic na geometrii czy materiałach, ponieważ callback w trakcie filtrowania IFD może to zrobić za Ciebie, musisz tylko mieć odpowiedni eksport na shaderach (i plane'y dodane "na zapas").

 

 

Jest pewnie kilka innych metod. W naszym pipelinie nawet kompozytor mając listę materiałów lub obiektów, może spod Nuke'a sam puścić render potrzebnej maski (bo mając beaty pass wie, z jakiego ifd powstało, i może użyć go jeszcze raz z odpowiednim python filtrem), ale ta technika się nie przyjęła :)

 

Jak mówiłem, wszytko to jest nieco męczące. Mam nadzieję, że za chwilę ustali się jakiś standardowy format dla auto-mattów i będziemy mieli selekcje obiektów i materiałów w kompozycji w standardzie.

Edited by SYmek
Link to comment
Share on other sites

Wow, dzięki za wyczerpujące wyjaśnienie. Widziałem te Cryptomatty od PsyOpa, już dłuższy czas temu się tym chwalili. Myślałem że mogę łatwo zautomatyzować swoje prościutkie rozwiązanie, ale skoro nie, to chyba chwilowo przy nim zostanę. Wszystko o czym piszesz to na razie za wysokie progi dla mnie ;]

Link to comment
Share on other sites

Wow, dzięki za wyczerpujące wyjaśnienie. Widziałem te Cryptomatty od PsyOpa, już dłuższy czas temu się tym chwalili. Myślałem że mogę łatwo zautomatyzować swoje prościutkie rozwiązanie, ale skoro nie, to chyba chwilowo przy nim zostanę. Wszystko o czym piszesz to na razie za wysokie progi dla mnie ;]

 

Łatwo jak łatwo. Niestety, jakie materiały będą wykorzystane w scenie wie dopiero naprawdę SOHO, i customizacja SOHO to byłaby prawdopodobnie najlepsza metoda (można zarówno znaleźć wszystkie eksporty jak i dodawać plane'y). Houdini jest po prostu zbyt skomplikowany... na przykład materiału, który będziesz renderował w ogóle może nie być w scenie (delayed load albo packed prims). Przejrzeć materiały, które są w /shop jest łatwo, dodać plane'y też, ale które z tych materiałów będą użyte trywialne już nie jest, bo jest za wiele metod ich aplikacji.

 

Załączam małą ilustrację. Powinno działać z materiałami object level i primitive level, ale skrypt już musi iterować po wszystkich prymitywach w scenie... słabo, a jeszcze materiały per punkt, i na packed prims... chyba że się założy, że parsujemy parametry MaterialSOP tylko, będzie szybko, ale nie zadziała dla obiektów na dysk (które mają atrybuty już na sobie)... czyli soho, albo filtr IFD

 

 

rop = hou.node("/obj/out").selectedChildren()[0]
candidates_obj  = [obj for obj in hou.node("/obj/").recursiveGlob(rop.parm("vobjects").eval(), \
   filter=hou.nodeTypeFilter.Obj) if obj.isObjectDisplayed()]
# to samo dla force object....
candidates_sops = [obj.renderNode() for obj in candidates_obj]
prim_materials  = [attrib for attrib in sop.geometry().primAttribs() \
   for sop in candidates_sops if attrib.name() == 'shop_materialpath']
prim_materials  = list(set([prim.attribValue(attrib) for prim in \
   attrib.geometry().prims() for attrib in prim_materials]))
obj_materials   = [hou.node(obj.parm("shop_materialpath").eval()) for obj in candidates_obj]
materials       = list(set(prim_materials + obj_materials))


# Teraz pętla dla materiałów:
idx = rop.parm("vm_numaux").eval()
rop.parm("vm_numaux").set(rop.parm("vm_numaux").eval() + len(materials))
for mat in materials:
   variable_name = 'vm_variable_plane'   + str(materials.index(mat) + idx)
   channel_name  = 'vm_channel_plane'    + str(materials.index(mat) + idx)
   export_name   = [parm.eval() for parm in mat.parms() \
       if parm.name().startswith("MASK_")] # Zakładam, że export nazywa się jak pewien parameter. whatever.
   rop.parm(variable_name).set(export_name)
   rop.parm(channel_name).set(export_name)
   # itd

Link to comment
Share on other sites

Super, dzięki! Jeśli materiały SOPowe są brane pod uwagę, w zupełności mi to wystarczy.

 

Chodziło mi o nawet prostszą sytuację. Powiedzmy że wszystkie obiekty mają ten sam materiał, ale każdy ma unikalny atrybut o wartości jeden. W materiale wszystkie te parametry wczytuję i eksportuję do image planów. Jeśli dobrze widzę, druga część Twojego skryptu w zasadzie robi już to czego potrzebuję.

 

Zastanawiam się jeszcze czy zamiast ręcznie tworzonych atrybutów nie dałoby się wykorzystać po prostu nazwy obiektu.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now



×
×
  • Create New...

Important Information

We are using cookies. Read about our Privacy Policy