Sverchok / SverchokRedux

A reimplementation of Sverchok
GNU General Public License v3.0
4 stars 2 forks source link

Ideas about nodes #3

Open ly29 opened 9 years ago

ly29 commented 9 years ago

This isn't a finished model.

  1. UI and execution should be separated
  2. The execution unit, in which ever form, it takes shouldn't have to access the node but be created with it as input.
  3. Individual nodes shouldn't parse the whole data tree (in general) but only individual bits of data
  4. For practical purposes the most meaningful size of individual data is the mesh, a lot of data is only valid for
  5. A lot of flexibility and possibility would come from building the possibility of serializing the data into the system.

How should this be accomplished?

Let us at looks some different models to create nodes.

SN1

import numpy as np

def sv_main(n_items=1500, q_factor_x=2, q_factor_y=2, seed=6):

    in_sockets = [
        ['s', 'n_items', n_items],
        ['s', 'q_factor_x', q_factor_x],
        ['s', 'q_factor_y', q_factor_y],
        ['s', 'seed', seed]]

    np.random.seed(seed)
    points=np.random.uniform(0.0,1.0,size = (n_items,2))
    points *= (1000, 200)

    a = points[:,0]
    b = points[:,1]
    a = np.floor(a / q_factor_x) * q_factor_x
    b = np.floor(b / q_factor_y) * q_factor_y
    c = np.array([0.0 for i in b])
    d = np.column_stack((a,b,c))

    # consumables
    Verts = [d.tolist()]

    out_sockets = [
        ['v', 'Verts', Verts]
    ]

    return in_sockets, out_sockets

SN2

from itertools import chain

class DeleteLooseVerts(SvScriptSimpleFunction):
    inputs = [("v", "verts"), ("s", "pol")]
    outputs = [("v", "verts"), ("s", "pol")]

    @staticmethod
    def function(*args, **kwargs):
        ve, pe = args       
        indx = set(chain.from_iterable(pe))
        v_index = sorted(set(chain.from_iterable(pe)))
        v_out = [ve[i] for i in v_index]
        mapping = dict(((j, i) for i, j in enumerate(v_index)))
        p_out = [tuple(map(mapping.get, p)) for p in pe]
        return v_out, p_out
shader gabor_noise(
    point Point = P,
    vector Direction = vector(1, 0, 0),
    int Anisotropic = 0,
    float Bandwidth = 1.0,
    float Impulses = 16,
    output float Gabor = 0.8)
{
    Gabor = noise("gabor", Point,
                  "direction", Direction,
                  "anisotropic", Anisotropic,
                  "do_filter", 1, // Set to 0 to disable filtering/anti-aliasing 
                  "bandwidth", Bandwidth,
                  "impulses", Impulses);
}

Basically there are more or less identical, as I see the most easily inspectable one with types etc is more complex SN2.

What I propose is a python class that provides a functional unit that can be executed on individual pieces of the mesh.

nortikin commented 9 years ago

vectorization on some level. main levels of vectorizations - objects and their values. we ned convention

zeffii commented 9 years ago

as a model for generating mesh data I still really like SN1's simplicity, but it's rubbish not the most convenient as a modifier of incoming nested data, am quite happy not to bring SN1 to Redux. (potentially a loader to hoist the sv_main function as a class member of a class proper would be interesting to code )

ly29 commented 9 years ago

@zeffii Yeah I also like SN1 and osl more style more.

@nortikin please explain a bit more about your thoughts here, vectorization is a main concern of course and most nodes shouldn't have to support it.

nortikin commented 9 years ago

@ly29 inputs as [1,2,3][1,2] have to produce two objects with three and two vertices i.e., and it have to occure on all nodes, plus 1 level is objects level, have to be defined by default and deal with objects in all nodes. it is rules

ly29 commented 9 years ago

@nortikin Yes, that is one of the main issues that we to fix. The names of things might change a bit but such things will be possible by default, always, for all nodes.

ly29 commented 9 years ago

We could even have multiple forms for writing nodes as long as they can describe themselves properly. But a standard form is better.

zeffii commented 9 years ago

Some nodes (minority) would be really short to describe because they are essentially Effects. Take Remove Doubles or Intersect Edges, nodes like that could be described in an eval/exec form like

from svrx_base_modules import intersect_verts_edges

inputs("verts")  # this named input is special and will always generate a V input
inputs("edges")  # now StringProperty, probably we should call it NestedPropery, or IndicesProperty
a, b = intersect_verts_edges("verts", "edges")
outputs("verts", a) 
outputs("edges", b)

Remove doubles:

from svrx_base_modules import remove_doubles

inputs("verts")
inputs("edges")
inputs("faces")
distance = ui_slider("distance", dict(default=0.0001, min=0.0))
a, b, c = remove_doubles("verts", "edges", distance)
outputs("verts", a) 
outputs("edges", b)
outputs("faces", c)

or

from svrx_base_modules import remove_doubles

v = inputs("verts")
e = inputs("edges")
f = inputs("faces")
distance = ui_slider("distance", dict(default=0.0001, min=0.0))
a, b, c = remove_doubles([v, e, f], [distance])
outputs("verts", a) 
outputs("edges", b)
outputs("faces", c)

or even more common

from svrx_base_modules import remove_doubles

v, e, f = inputs("verts", "edges", "faces")
distance = ui_slider("distance", dict(default=0.0001, min=0.0))
a, b, c = remove_doubles([v, e, f], [distance])
outputs("verts", a) 
outputs("edges", b)
outputs("faces", c)

or taking that abstraction further by using Mesh to mean verts, edges, faces

from svrx_base_modules import remove_doubles

# 'mesh' would auto inflate to `verts, edges, faces` sockets

v, e, f = inputs("mesh")
distance = ui_slider("distance", dict(default=0.0001, min=0.0))
a, b, c = remove_doubles([v, e, f], [distance])
outputs("mesh", [a, b, c]) 

here intersect_verts_edges and remove_doubles can be defined with zero knowledge of where they're called from..

Then i start to think adding the UI can be a separate file...or section in the same file

from svrx_base_modules import remove_doubles

v, e, f = inputs("mesh")

svrx_prop1 = StringProperty(name='prop1')
svrx_prop2 = IntProperty(name='prop2')
params = [svrx_prop1, svrx_prop2]

def draw(self, context):
    ... # optional, will draw props in order of appearance in params list.

a, b, c = remove_doubles([v, e, f],  params)
outputs("mesh", [a, b, c]) 
zeffii commented 9 years ago

a good time to rethink the naming convention of our socket types. StringsSocket needs to go.

ly29 commented 9 years ago

StringsSocket is out for sure.

the whole getting data from socket paradigm has to go I think, the node execution unit should be called with the relevant data, for its execution type.

The socket is an indication of data type, not a guarantee unless we enforce type safety on top of python which to me, doesn't seem worth it.

I general I would like to store the blender properties in the socket, not in the node, but this has some limitations so am not sure about it. The problem of course being the we would have to generate a new socket type for each case of say limits in the float property. I wish properties could be individually adjusted with default/min/max etc

zeffii commented 9 years ago

I general I would like to store the blender properties in the socket,

right i get ya!

ly29 commented 9 years ago

Socket Types

ly29 commented 9 years ago

For now I think pynodes are workable but writing our own nodes thing would be a nice challenge.

zeffii commented 9 years ago

can we not combine Matrix/Euler/Quaternion as TransformsConstructs, where the socket/stream has a mode. (just wondering if the separation is needed.. )

zeffii commented 9 years ago

I think Curve data would be great too, 10 socket types isn't too bad.. I think @nortikin had objections to raising the socket count?

ly29 commented 9 years ago

Node -> Dict and Dict -> Node

Ideally this should be two parts, one being the blender properties ui location, dimension, the other being the properties of the node as relevant to sverchok execution.

@zeffii A certain amount of sockets is needed I think, the other approach to having many socket types is too have one socket for everything which isn't a good option. I don't think we should enforce type safety however, if you want use color data as vertex locations go ahead.

zeffii commented 9 years ago

I don't think we should enforce type safety however, if you want use color data as vertex locations go ahead.

yeah, this fuzzy logic has many positive uses, and it mirrors the behaviour of the shader node trees

ly29 commented 9 years ago

exactly

ly29 commented 9 years ago

I also think we should copy the socket naming convention from the rest of blender i.e. Name instead of name, that being more controversial I understand.

nortikin commented 9 years ago

about names - propose tolimit names lenght to 5-6 maximum 8 in Grasshopper there are 1-letter names wich is not cozy, better to inform user in 4 characters, he will understand. Vers Edgs Pols Mats (it is better to stay with its name but put there Euler and quaternion i guess) Float Int Obj Curv Str Bmesh ID (with explanation - it is blender ids) Color and additionaly short: Norm Tang Centr Mask Index Vdonor Vrecip

Have to admit we need basic sockets to be defined, not to use verts+pols in one node and bmesh or obj in other. it should be some kind of basic data-paradigm. If we use bmesh as second basic in hierarhy than obj have to have switch or something like converter we have to have in any case. more types more probllems. Obj and ID can they be combined? And bmesh can be used instead of verts and polygons? we can use bmesh in general cases on modifiers and analyzers, list functions and others, but when generating or work with lowlevel data we need decompose object to bmesh (obviouse it is basic socket) and matrix and than to vertices and polygons and edges and than vertices to digits.

Sorry for many characters

nortikin commented 9 years ago

the problem of matrix generator and matrix deform node is not obviouse for user - second float socket for rotation can eat vertex (or vector wich is second problem how to name). Or we can add Vers in socket class as we do with dot and number of objects, than we have not headake how to name, but have to define behaviour of labeling - in node name Vers becomes Vers. in labe but name Norm becomes VersNorm. in label for example, or node-creator's name Centr becomes VersCentr.12

nortikin commented 9 years ago

now we have to collect all issues to mind-map, because it helps a lot, at least for me.

zeffii commented 9 years ago

On UI I prefer proper names or sensible shortnames. I think 'vers' is not the best. 'verts' is one letter extra and actually means something in English. Similarly with Edges what's the problem with the extra e? I think the 8 letter max is good, but trying to make shortnames to save one letter if it's already under 8 characters is not so pretty.

nortikin commented 9 years ago

you know English better anyway, let it bee. :+1:

zeffii commented 9 years ago

polys, bm, VNorm, FNorm

zeffii commented 9 years ago

but agreed that simply one letter like grasshopper is a bit too economical :)

zeffii commented 9 years ago

it would be awesome if socket nipples had a hover state which could trigger a tooltip for that socket, I haven't seen that anywhere, in blender , but would be handy.

nortikin commented 9 years ago

https://gist.github.com/nortikin/eace3b46e85c585b06a0 this has to be in one node (not formula shape node, but make surface from two vertices sequences)

nortikin commented 9 years ago

@zeffii even not imagin how. OpenGL popups?

ly29 commented 9 years ago

I think is 8 shorter max than needed, for example in one of the most used nodes a socket is called Displacement. Anyway I can live with 8 but agree with @zeffii about clarity.

tooltips would be nice.

@nortikin While such node is needed let us keep this discussion on a more fundamental level

zeffii commented 9 years ago

i'm not fussy about going over 8 characters, if it's acceptable for standard Blender nodes, as @ly29 mentions 'Displacement' is 12 and i've never considered that too long. After a while of using new nodes your brain doesn't really read them any more, it works more on position (if the node isn't dynamically naming sockets )

zeffii commented 9 years ago

about fuzzy sockets, I think Matrix socket should accept and implicitly convert Locations / Vectors to a Translate Matrix, this would allow convenient

rather than

ly29 commented 9 years ago

Such conversion rules should be supported.

zeffii commented 9 years ago

@ly29

I wish properties could be individually adjusted with default/min/max etc

yeah, this is such a pain, but perhaps it is possible to simply assign a dynamically added Property to a node along the lines of

    some_prop = IntProperty(min=0, max=20, step=2)

    #later 
    stored_value = copy.copy(self.some_prop)
    del self.some_prop
    self.some_prop = IntProperty(min=0, max=40, step=4)
    self.some_prop = stored_value

del is not supported

nortikin commented 9 years ago

@zeffii again, rna, not id, maybe node can have id property on fly? oh, no it cannot, for sure

nortikin commented 9 years ago

@ly29 material socket with texture assigned to it? we can make unwrap with python, maybe someone wish to assign material and unwrap exact polygon of bmesh (when we decompose bmesh to vertices polygons we lost unwrap layout data and others how to solve?)

zeffii commented 9 years ago

I was under the impression that if you have a list of edges from obj.data.edges, say like edges [0,1,4,5,6,10], and then take a bm representation of obj.data , the edges on indices of bm.edges are not the same as obj.data.edges, the only shared data are bm.verts and obj.data.vertices, bm itself seems to just mangle them for speed reasons. (But ! I do recall seeing a sort function in the bmesh code)

ly29 commented 9 years ago

@nortikin I think we might work with bmesh for that.

nortikin commented 9 years ago

might but appears several ways to deal to sverchok - first is usual low level, second is bmesh, third objects and scene. Or maybe whan we edit in low level than bmesh not deleted during layout but updated its data - changed vertices - making ensure lookup table and output it? so every bmesh decomposition must meet node called change bmesh data? it becomes difficult but not see how to deal in other way with bmesh.

nortikin commented 9 years ago

or we deal with data as container with bmesh,matrix,verts,edges,polygons,textures,materials etc. and pipeline of processing layout only change some part of it even if it is not presented as bmesh socket? so from start to end we deal with object containing bmesh? not sure, because we can devide one mesh to parts and how than? allready problem is how to view bmesh and change it after viewing, we need get it from scene again, it must not happend

zeffii commented 9 years ago

after adding any verts + edges + face manually to a bm we must call bm.<type>.ensure_lookup_table(), i'm not positive it is needed excplicitly when doing a bmesh.ops operation

ly29 commented 9 years ago

Some of the problems you see I don't see. However it is not the stage I am at the moment. I think some things will resolve themselves, some will not however. But then we try to solve them then, incrementally.

nortikin commented 9 years ago

guys, we also need vector socket that will have: [x,y,z][dx,dy,dz] and optionally dx,dy,dz can be normalized vector but additionally we can add strength or capasity of each vector in length single value so plain list will consists of 7 numbers [x,y,z,dx,dy,dz,c,...] we can teach viewers to display them (Jimmy Gunnavan asked long ago).

zeffii commented 9 years ago

but dx, dy, dz can be inferred at calculation time, it can be a simple separate additional structure for np_Mesh to produce when asked. Storing that information explicitely and allways is not necessary. If we have a node that uses deltas then it can call a function and store all the result to the np_mesh.delta_vectors array or something.

or make it possible to push an array of deltas at any time onto np_Mesh, same with 'weight' (capacity) w. Separate stream included in np_Mesh.

nortikin commented 9 years ago

who knows what else will be needed - vertex colors can be coded just like thhat, so additional dictionaries needed extremely, maybe globally it will cover curve type of data -with addtional handles to knots, so you will have additionally two lists with identical looku table for level 2,3,4... so level 1 wil only lookup as 3 or 1 or 2 numbers depends on what we need. for one object one lookup table wich will decrease memory usage. cool.

ly29 commented 9 years ago

Function annotations seems perfect for type info... https://docs.python.org/3/tutorial/controlflow.html#function-annotations

def f(a : int = 2, b: float = 3.0) -> (float, float):
    return b, b*a
>>> import inspect
>>> f.__annotations__
{'b': <class 'float'>, 'a': <class 'int'>, 'return': (<class 'float'>, <class 'float'>)}
>>> sig = inspect.signature(f)
>>> str(sig)
"(a:int=2, b:float=3.0) -> (<class 'float'>, <class 'float'>)"
ly29 commented 9 years ago

Furthermore in 3.5, will have to review a bit soonish. https://docs.python.org/3/library/typing.html

ly29 commented 9 years ago
import numpy as np

def linspace(start : float = 0.0, stop : float = 1.0, count : int = 10) -> ("linspace", np.array):
    return np.linspace(start, stop, num)

Something like this could be a complete node for simple cases, like node scripts. Annotations are amazing (not really but a very nice feature). UI could be generated from this. Of course this isn't enough for every node but could go a long way.

@zeffii It would make script node mk1 clearer.

zeffii commented 9 years ago

yeah, I would like to commit to doing a massive overhaul of mk1. Looking back at it it seems massively bloated. I'd like to think that I could do better, after a year and half :)

But unfortunately my mother has been seriously ill for a few months and will be operated on tomorrow for the n-th time ... the outcome of which will greatly influence how much time I can commit to this.. and how clear i'll be able to think.

ly29 commented 9 years ago

I am sorry to hear about your mother. Take care.

I have been busy lately but I want to boot strap this now, the ideas have been brewing in my head. Yeah, we do learn a lot. Have to get into it again, want at least try some of them out.

I like the fact the fact that with this we could basically have an OSL like simplicity.

zeffii commented 9 years ago

Thanks @ly29 . Difficult times, but I do like the distractions and it's why i've been coding in the open a bit more again.

I'm interested to see a less complicated back-end for SN MK1, and wouldn't feel obliged to retain any form of backwards compatibility, scripts should be easy to convert as and when they are needed. Afterall the interface is what would change, the work-code mostly remains unchanged.

Having some typed interface, is kind of what sn mk1 already has, but making it explicit is something i'm all for. (Even if we have to allow custom data types... float vs list..vs np array etc :)