sverchok / sverchok Goto Github PK
View Code? Open in Web Editor NEWA node based system for geometry in Blender
License: GNU General Public License v3.0
A node based system for geometry in Blender
License: GNU General Public License v3.0
i propose not having the draw function inside the callback class, but pass it like this
https://github.com/nortikin/sverchok/blob/5c052118b8b1f42c7d4bc8821ad3ca855d1ddde0/nodes/number/easing.py#L147-L179
# end early
nvBGL2.callback_disable(n_id)
...
if self.activate:
x, y = [int(j) for j in (self.location + Vector((self.width + 20, 0)))[:]]
draw_data = {
'tree_name': self.id_data.name[:],
'custom_function': simple_grid_xy,
'loc': (x, y),
'args': (easing_func, palette) # or whatever args
}
nvBGL2.callback_enable(n_id, draw_data)
Opening the gates for nodes that needs to be implemented, priority will be to the ones forcing new issues to be resolved.
Also of course some nodes might needed to be pushed back until issues are resolved, either by working differently or by resolving, potentially systematic issues.
Please add things here.
Basic generator nodes
Math
List
Topology
flip polygons
node (non bm) / with mask
The old Sverchok nodes
https://github.com/nortikin/sverchok/blob/master/index.md
New sverchok 0.5.9 nodes that should be remade for Rx.
In the previous implementation the node was implemented manually not fully working with the same interfaces and simplicity as other nodes. So we introduce a class decorator called @stateful
@stateful
class MeshOut():
bl_idname = "SvRxNodeMeshOut"
label = "Mesh out"
def __init__(self):
self.start()
def start(self):
self.verts = []
self.edges = []
self.faces = []
def stop(self):
obj_index = 0
# using range to limit object number for now during testing
for idx, verts, edges, faces in zip(range(100), self.verts, self.edges, self.faces):
obj_index = idx
make_bmesh_geometry(verts[:, :3], edges, faces, idx=idx, normal_update=False)
# cleanup
self.remove_non_updated_objects(obj_index)
def __call__(self, verts: Vertices = Required, edges: Edges = None, faces: Faces = None):
self.verts.append(verts)
self.edges.append(edges)
self.faces.append(faces)
def stateful(cls):
func = cls()
get_signature(func)
class InnerStateful(cls, Stateful):
inputs_template = func.inputs_template.copy()
outputs_template = func.outputs_template.copy()
properties = func.properties.copy()
parameters = func.parameters.copy()
returns = func.returns.copy()
func_new = InnerStateful()
class_factory(func_new)
InnerStateful.node_cls = func_new.cls
_node_classes[cls.bl_idname] = InnerStateful
return InnerStateful
Never having done any class decorators before I was little bit surprised about the technique.
Vertices -> [Matrix]
n
gives (n, n, n, 0)
. Number -> Vertices
[Matrix] -> Vertices
or Matrix -> Vertices
, not entirely sure about itI don't want the number of conversion to be to big and want the rules to be clear and easy to understand, there as an help. For ambiguous situation is better to require clarity. So point out additional rules would be good or suggest a way for socket to show that it can handle multiple types.
Want I don't want to happen is like the old Matrix In node where there is totally invisible functionality available in only one place that is impossible to predict from the UI. I would be better with some different modes for matrix in providing sensible variations.
Handling of errors in current sverchok is... well... not very good. To understand why the node goes red you need to switch to console and try to understand the stacktrace saying smth like "index -1 is out of bounds".
I think the big refactoring is good time to think about better way of handling errors.
Looking into svrx.typing
one quickly sees reason for concern. Many of the names are pretty generic and clashes with blender ````mathutils```. Names in particular that need replacement.
Doing that starting out decided to just pick natural names and it mostly worked out. But some suggestions for avoid doing things like below.
import mathutils as mu
mat = mu.Matrix()
# or even worse
import svrx.typing as t
@node_func
def transform(vert: t.Vertices = None, mat: t.Matrix) -> t.Vertices:
So this worked in OS X but not on windows 10, both blender 2.78a.
@node_func(bl_idname="SvRxMatrixTransform")
def transform(vertices: Vertices = Required,
matrix: Matrix = Matrix.identity
) -> Vertices:
return vertices @ matrix.T
TypeError: unsupported operand type(s) for @: 'numpy.ndarray' and 'numpy.ndarray'
The idea here is to provide a sufficient amount of nodes that system is usable and can be evaluated beyond totally technical details. A rough outline below based on templates from sverchok.
Multisocket is allowing a dynamic amount of inputs into a node, like list join and formula node.
@node_func(...)
def formula_node(x: Float = 1.0, *n: Float)-> Float:
pass
Changing socket type is basically allowing type information to be carried forward over generic socket links. A kind of generics basically.
def split(size: Int = 1, data: Anytype = Required) -> [Anytype("Data", input=1)]:
pass
import bmesh
from svrx.util.geom import vectorize
from svrx.util.mesh import rxdata_from_bm
@vectorize
def make_icosphere(subdiv, diam):
bm = bmesh.new()
bmesh.ops.create_icosphere(bm, subdivisions=subdiv, diameter=diam, calc_uvs=False)
return rxdata_from_bm(bm)
@node_script
def sn_icosphere(subdiv: Int(min=0, max=5) = 3, diam: Float = 1.0) -> ([Vertices], [Edges], [Faces]):
return list(make_icosphere(min(subdiv, 5), diam))
Like so.
It is another one of these things that is easier to get started with early, parsed the node functions a bit to generate something for docs. It would be ideal if at least the inputs description could be auto generated from the source, images and examples could be manually added, I don't want to full numpy docstring, at least not yet.
----------
Node: Linear Spline
Inputs:
name : default: type
verts : None : Vertices
t : 0.5 : Float
Outputs:
Vertices : Vertices
----------
All nodes
https://gist.github.com/ly29/08a1c2d5ab4a925183245e7b7e8d937d
I don't think we are quite at that stage yet but want to air ideas.
A master todolist, feel free to add things, but this is for general features not specific nodes. Only specific nodes that have consequences for the system.
All these things should be reconsidered before inclusion, some are independent and and can be moved mostly without problem, some require deeper thinking
There will be times we might this kind of conversion instead of writing something as np immediately, just to get something working quickly, some esoteric generator.
https://github.com/Sverchok/Sverchok/blob/master/util/smesh.py
i'd like to get stuck into the SMesh.from_pydata
and SVertices.from_pydata
,
To have two types SMesh
and BMesh
which are considered compatible and converted as needed by the system.
SMesh is an Sverchok representation of a mesh using flat numpy
storage.
The two types would have the same socket representation but the mesh data would be converted as needed. Perhaps also allow overload for certain functions and have two functions to avoid conversion.
To the user and the nodes this would basically be invisible, the intelligence would be in the base system
A partial sample implementation of a mesh using np storage
https://github.com/nortikin/sverchok/blob/polygon_flat/utils/polygon.py
Some timings, non optional in branch right now, prints into SVRX_timings text file in blender
Total exec time: NodeTree 9.523e-03
DAG build time: 2.859e-04 3.0%
SvRxGeneratorTopology: Topology 1.464e-03 15.4%
SvRxVirtualNode: VNode<Create Matrix> 1.649e-03 17.3%
SvRxNumberLinspace: Linspace.004 1.425e-04 1.5%
SvRxNodeMeshOut: Mesh out 3.677e-03 38.6%
SvRxMatrixTransform: Transform 2.871e-04 3.0%
SvRxNodeTrig: Trig 5.888e-05 0.6%
SvRxNodeVectorIn: Vector In 8.064e-05 0.8%
SvRxNodeMath: Math 5.333e-05 0.6%
SvRxNodeCircle: Circle 1.796e-03 18.9%
Node call time total: 9.208e-03 96.7%
Sincos 1 8.533e-06 0.1%
Transform 20 8.107e-05 0.9%
Linspace 1 6.827e-05 0.7%
Mesh out 1 2.560e-06 0.0%
Add 1 1.067e-05 0.1%
Cylinder 1 1.390e-03 14.6%
Vector In 1 2.133e-05 0.2%
Circle 1 1.677e-03 17.6%
Create Matrix 1 1.550e-03 16.3%
Functon call total time 4.809e-03 50.5%
verts only... almost
import numpy as np
from svrx.util.geom import generator
from svrx.util.smesh import SvVertices
def make_torus(R, r, N1, N2):
t1 = np.linspace(0, np.pi * 2 * (N1 - 1 / N1), N1)
t3 = np.tile(t1, N2)
r1 = np.sin(np.linspace(0, np.pi * 2 * (N2 - 1 / N2), N2))
r3 = np.repeat(r1, N1) * r + R
r2 = np.repeat(np.cos(np.linspace(0, np.pi * 2 * (N2 - 1 / N2), N2)), N1)
circ = np.array([np.cos(t3)*r3, np.sin(t3)*r3, r2*r, np.ones(N1*N2)])
verts = np.transpose(circ)
return verts, None, None
@node_script
@generator
def sn_torus(
R: Float = 2.0, r: Float = 0.6,
N1: Int = 22, N2: Int = 15) -> ([Vertices], [Edges], [Faces]):
return list(make_torus(R, r, N1, N2))
Hi, folks. Using hex grid appear an idea for svrx
Any suggestions how to implement?
And if we vectorize simulateously several levels, how to do?
Interface will include operation level slider for all nodes maybe and add it in generic node
let's go name + str("%04d" % idx)
padding to 4 numbers
and
obj['idx'] = idx
obj['basename'] = node.basemesh_name
that solves all the tricky finding/removing stuff.
The type system right now is as seen below. It is meant to provide metadata for the execution system and as basis for conversion between types. Dynamic typing is not allowed, however changing type based on setting in a node is allowed. A kind of generics is allowed.
Type | Socket class | data description |
---|---|---|
Color | SvRxColorSocket | np.float64 shape=(N, 4) RGBA |
TopoData | SvRxTopoSocket | Generic topological data |
Edges | SvRxTopoSocket | np.uint, shape = (N, 2) |
Faces | SvRxTopoSocket | SFaces class see #6 |
SMesh | SvRxMeshSocket | SMesh see #6 |
BMesh | SvRxMeshSocket | Bmesh |
Object | SvRxObjectSocket | Blender obj reference |
Number | SvRxFloatSocket | Generic number |
Matrix | SvRxMatrixSocket | np 4x4 Matrix |
Anytype | SvRxAnySocket | Generic type |
String | SvRxStringSocket | str |
Int | SvRxIntSocket | np.int shape = (N,) |
Float | SvRxFloatSocket | np.float64 shape = (N,) |
Vector | SvRxVectorSocket | np.float64 shape=(N,4), used for when you want a vector |
Vertices | SvRxVertexSocket | np.float64 shape=(N,4) |
This thread aims to test and push development by giving existing examples to replicate
Memphis, TN: The Hernando-DeSoto Bridge, aka the "M" Bridge
https://goo.gl/images/F2jBCb
Sagamore Bridge, Cape Cod Canal - Bourne
https://goo.gl/images/WfWidM
Helix Bridge Singapore
https://goo.gl/images/dplRS6
forgot to add the file?
One of things that current Sverchok lacks is proper internationalization. Afaik Blender allows to use some kind of gettext for everything. Can we use the same for Sverchok? This global refactoring might be a good time to introduce such a feature.
svrx\util\transforms.py:1899: UserWarning: failed to import module _transformations
warnings.warn("failed to import module %s" % name)
They should be extended into more useful form at least matching float range and int range from N1.
Many functions that we want to expose fall into logical groups that it doesn't make sense to break apart into multipile nodes even though the function are different and in many cases also the function signatures.
For example math nodes and different sort modes.
One, simple option is below, which I feel might be appriate for nodes that keep the same signature but change mode.
from svrx.nodes.node_base import node_func
from svrx.typing import Number, Float, Int, EnumP
mode_list_tmp = [('ADD', 1), ('SUB', 2)]
mode_list = [(t, t, t, idx) for t, idx in mode_list_tmp]
@node_func(bl_idname='SvRxNodeNumberMath')
def math(x: Number = 0.0, y: Number = 0.0,
mode: EnumP(items=mode_list, default='ADD') = 'ADD')-> Number:
f = func_lookup[mode]
return f(x, y)
def add(x, y):
return x + y
def sub(x, y):
return x - y
func_lookup = {'ADD': add,
'SUB': sub, }
However I don't feel this is good enough so will work a bit on this today.
Inspired by nortikin/sverchok#1248
import numpy as np
import bpy
from svrx.util.function import array_as
def assign_image(image, size ,buffer):
np_buff = np.empty(len(image.pixels), dtype=np.float32)
np_buff.shape = (-1, 4)
np_buff[:,:] = buffer[:,np.newaxis]
np_buff[:,3] = 1
np_buff.shape = -1
image.pixels[:] = np_buff
return image
@node_script
def texture(value: Float = 0.5,
size: Int = 64,
name: String = "texture"):
image = bpy.data.images.get(name)
if not image:
image = bpy.data.images.new(name, size, size, alpha=False)
image.pack
else:
image.scale(size, size)
new = array_as(value, (size*size,))
assign_image(image, size, new)
image.update_tag()
Following the mostly successful multi modal node experiment in #11 I now turn to the basic node set starting with math nodes.
In the old Sverchok I think perhaps math node got to many modes, there are 44 and the menu is somewhat hard to navigate.
I propose to split up trigonometry into a different node directly since it is clear divide to make is somewhat more resonable, for now I will not add all functions directly...
See #25 for the current pullrequest for Math node. And modes which are fully or partially implemented
See #28 for Vector Math node branch / PR.
currenty the < 0.6 sverchok has a moderately large list of mesh generators, but they aren't organized as tidy as they could be.
I wonder might we do a similar separate menu like Object Add for primitives, with a similar categorization. (the notable exception would be the Nurbs..which are not exposed very well in bpy)
To play around bit I did this.
A typical node ends up looking something like this.
@node_func(id=1)
@generator(mask=(1, 0))
def solidify(bm: BMesh = Required, thickness: Float = 1.0) -> [BMesh]:
bm = bm.copy()
geom_in = bm.verts[:] + bm.edges[:] + bm.faces[:]
bmesh.ops.solidify(bm, geom_in=geom_in, thickness=thickness)
return bm
Just the sv_init
function is longer.
https://github.com/nortikin/sverchok/blob/master/nodes/modifier_make/solidify.py
at the moment most of it works, but it doesn't display anything unless the input contains edges and meshes .
not sure why, haven't looked deeply.
For study the Mesh.from_pydata
method
def from_pydata(self, vertices, edges, faces):
"""
Make a mesh from a list of vertices/edges/faces
Until we have a nicer way to make geometry, use this.
:arg vertices:
float triplets each representing (X, Y, Z)
eg: [(0.0, 1.0, 0.5), ...].
:type vertices: iterable object
:arg edges:
int pairs, each pair contains two indices to the
*vertices* argument. eg: [(1, 2), ...]
:type edges: iterable object
:arg faces:
iterator of faces, each faces contains three or more indices to
the *vertices* argument. eg: [(5, 6, 8, 9), (1, 2, 3), ...]
:type faces: iterable object
.. warning::
Invalid mesh data
*(out of range indices, edges with matching indices,
2 sided faces... etc)* are **not** prevented.
If the data used for mesh creation isn't known to be valid,
run :class:`Mesh.validate` after this function.
"""
from itertools import chain, islice, accumulate
face_lengths = tuple(map(len, faces))
self.vertices.add(len(vertices))
self.edges.add(len(edges))
self.loops.add(sum(face_lengths))
self.polygons.add(len(faces))
self.vertices.foreach_set("co", tuple(chain.from_iterable(vertices)))
self.edges.foreach_set("vertices", tuple(chain.from_iterable(edges)))
vertex_indices = tuple(chain.from_iterable(faces))
loop_starts = tuple(islice(chain([0], accumulate(face_lengths)), len(faces)))
self.polygons.foreach_set("loop_total", face_lengths)
self.polygons.foreach_set("loop_start", loop_starts)
self.polygons.foreach_set("vertices", vertex_indices)
# if no edges - calculate them
if faces and (not edges):
self.update(calc_edges=True)
an interesting node to port over to redux.
In many cases when we want to generate some geometry, it's relatively easy to calculate vertex coordinates; but if there is a lot of vertices, then it's hard to figure out which vertex we need to connect to which. And this part of code can be most unintuitive.
What we can have in zero step is smth like
class VertexHandle(object):
def __init__(self, index, name=None):
self.index = index
self.name = name
class Mesh(object):
def add_vertex(self, vertex, name=None) -> VertexHandle:
...
def add_edge(self, VertexHandle, VertexHandle):
...
def add_face(self, *VertexHandle):
...
def to_rxdata(self):
...
def to_bmesh(self):
...
so that we could write smth like
mesh = Mesh()
a = mesh.add_vertex((1.0, 2.0, 3.0))
b = mesh.add_vertex((2.0, 2.0, 3.0))
c = mesh.add_vertex((3.0, 2.0, 3.0))
mesh.add_face(a,b,c)
...
return mesh.to_rxdata()
Data is stored in tree structure which knows its own type.
The data is described using levels which counts the distance from the leafs with data. The tree right now has an even depth but the structure might be irregular otherwise.
Current implementation of data storage is in core.data_tree
https://github.com/Sverchok/Sverchok/blob/master/core/data_tree.py
The node tree is then traversed in order as a acyclic graph. For the image above.
linspace.001, vector_in, linspace, Circle, create_matrix, transform, Mesh out
Here there is the possibility of being a lot more clever, to execute a sequences of nodes on a given level etc.
https://github.com/Sverchok/Sverchok/blob/master/core/execution.py#L52-L88
Each node is mapped to a function with provided metadata that can be called on each part of the data tree. Using a node.compile()
method that can return different functions based on the settings in the node.
For each node the data tree describing their input sockets are traversed using an longish recursive function. This is similar to what some old nodes like scalar math node does and some list nodes, most don't go as far.
https://github.com/Sverchok/Sverchok/blob/master/core/execution.py#L91-L143
The nodes themselves act upon the leaves or of the data tree and the output is assigned to data tree that are built during the recursion.
Nodes can be separated into 4 kinds.
Level nodes
def example(v: Vertices = None, s: Float = 1.0) -> Vertices
pass
Generators
A node that increases level is called an generator
, for example the circle node or linear space node. For each matched input it produces a separate output.
So circle(radius=[1.0, 2.0, 3.0], vert_nr=20)
creates three circles and a new level in the data tree.
Reducer nodes
An node that decreases the level is called an reducer
and takes a list a creates singular output. uv_connect(vert : [Vertices])
produces one Mesh object (also different signatures could be possible for uv_connect
Stateful nodes
A node that needs to be aware of the position of each fragment of the structure is called a stateful
node, for example mesh output that needs an index for naming.
For now that is pretty much it.
Did a quick test for drawing OpenGL with bmesh, went beyond expectation using the tessellated faces, then we only need to draw triangles.
All data is preprocessed in __call__
and only what to draw, colors etc is passed on to callback.
Very rough state and cannot control drawing on/off for specific features.
Also need a new callback handler or a refactoring of the current one.
array_inside_sverchok_004_2017_02_06_11_19.zip
I am making this node setup that generates like a TOTEM of Array. Each part of totem can be replaced randomly.
I made a MONAD out of it and trying to vectorize. But seems to fail. Wondering why...
Is this such a case where MONAD vectorize was not made for it.
So just started working on it.
Barely there but functional in the sense that you can load a script and it works.
Todo: (or what does not work)
file.py
and similar things)A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.