Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Marching_cubes with pymcubes, skimage and sverchok #1549

Closed
kalwalt opened this issue Apr 20, 2017 · 81 comments
Closed

Marching_cubes with pymcubes, skimage and sverchok #1549

kalwalt opened this issue Apr 20, 2017 · 81 comments

Comments

@kalwalt
Copy link
Contributor

kalwalt commented Apr 20, 2017

Pymcubes is a python module with a marching cubes algorithm. In the simple example that i provide it simply plot a sphere. You can set the bounds, the number of samples in each dimension, and the iso surface level. The sphere is defined by the function f; of course you can use what function you desire.
You must install the module in the python 3 location and then import it with the sys importing statement.

import sys
mcubes_path = r"/usr/local/lib/python3.5/dist-packages" #it depend on your OS but just paste the path where is mcubes
if not mcubes_path in sys.path:
    sys.path.append(mcubes_path)    
import mcubes

change your path accordingly.
to install pymcubes i used pip:

pip3 install pymcubes

it requires also pycollada and cython.

pymcubes_test

"""
in bounds s d=10 n=2
in iso_val s d=8.0 n=2
in samples s d=100 n=2
out vertices v
out triangles s
"""


import numpy as np
import sys
mcubes_path = r"/usr/local/lib/python3.5/dist-packages" #it depend on your OS but just paste the path where is mcubes
if not mcubes_path in sys.path:
    sys.path.append(mcubes_path)    
import mcubes

# Create the volume
def f(x, y, z):
    return x**2 + y**2 + z**2

# Create a data volume (30 x 30 x 30)
#X, Y, Z = np.mgrid[:100, :100, :100]
# u = (X-50)**2 + (Y-50)**2 + (Z-50)**2 - 25**2

# Extract the 0-isosurface
#verts, tri = mcubes.marching_cubes(u, 0)

# Extract the 16-isosurface
verts, tri = mcubes.marching_cubes_func(
        (-bounds, -bounds, -bounds), (bounds, bounds, bounds),  # Bounds
        samples, samples, samples,              # Number of samples in each dimension
        f,                          # Implicit function
        iso_val)                         # Isosurface value

vertices, triangles = verts.tolist(), tri.tolist()

you can take the script also here

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 20, 2017

multi_schwarz

multi schwarz ( i think it is called so...) with just a function call.
this is the formula used:

math.cos(x) + math.cos(y) + math.cos(z)

notice the isovalue used ( do not use high values).

script here

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 20, 2017

hyperboloid
hyperboloid with function:

x**2 + y**2 - z**2 - 0.3

@zeffii
Copy link
Collaborator

zeffii commented Apr 20, 2017

it can do metaballs? :)

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 20, 2017

it can do metaballs? :)

maybe, i will try to add a set of multi spheres,...

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 20, 2017

Bingo!
metaballs_test
with this script:

"""
in bounds s d=10 n=2
in iso_val s d=8.0 n=2
in samples s d=100 n=2
in factor s d=0.9 n=2
out vertices v
out triangles s
"""


import numpy as np
import sys
mcubes_path = r"/usr/local/lib/python3.5/dist-packages" #it depend on your OS but just paste the path where is scipy
if not mcubes_path in sys.path:
    sys.path.append(mcubes_path)    
import mcubes
import math

# Create the volume
def f(x, y, z):
    
    return ((x-factor)*(x-factor)+y*y+z*z-1)*((x+factor)*(x+factor)+y*y+z*z-1)-0.3

# Extract the 16-isosurface
verts, tri = mcubes.marching_cubes_func(
        (-bounds, -bounds, -bounds), (bounds, bounds, bounds),  # Bounds
        samples, samples, samples,              # Number of samples in each dimension
        f,                          # Implicit function
        iso_val)                         # Isosurface value

vertices, triangles = verts.tolist(), tri.tolist()

This only create two spheres but it can be developed a multi spheres version.
https://github.com/kalwalt/sverchok_nodes_collection/blob/master/scripts/pymcubes/metaballs_test.py

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 20, 2017

Scikit image module has also marching cubes functions http://scikit-image.org/docs/dev/auto_examples/edges/plot_marching_cubes.html
but i didn't tryed yet. I found this modules as possible replacement for polyvox lib that i used before #1168 as this has some issues....

@zeffii
Copy link
Collaborator

zeffii commented Apr 20, 2017

i'd like to see an example of multi verts for metaballs. very cool stuff.

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 20, 2017

i'd like to see an example of multi verts for metaballs. very cool stuff.

i will do later if i can.

@nortikin
Copy link
Owner

hm, will try at home just essentially needed stuff

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 20, 2017

ok thank you. I'm looking for the multi metaballs example.
one difficult is that the function f must be in the form f(x, y, z) as described in the struct of the pywrapper.ccp:

struct PythonToCFunc
{
    PyObject* func;
    PythonToCFunc(PyObject* func) {this->func = func;}
    double operator()(double x, double y, double z)
    {
        PyObject* res = PyObject_CallFunction(func, "(d,d,d)", x, y, z); // py::extract<double>(func(x,y,z));
        if(res == NULL)
            return 0.0;
        
        double result = PyFloat_AsDouble(res);
        Py_DECREF(res);
        return result;
    }
};

https://github.com/pmneila/PyMCubes/blob/master/mcubes/src/pywrapper.cpp#L8

@scorpion451
Copy link

anyone know a reason the script would fail to load mcubes on Windows?
I swapped out the file path to "C:\Program Files\Python36\Lib\site-packages" but it keeps giving me an error about not being able to find mcube._mcube

@enzyme69
Copy link
Collaborator

enzyme69 commented Apr 21, 2017 via email

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 21, 2017

@scorpion451 i don't know. But where is mcubes folder? in

C:\Program Files\Python36\Lib\site-packages

?

in my mcubes folder i have three files:

exporter.py
__init__.py
_mcubes.cpython-35m-x86_64-linux-gnu.so  # _this in Windows should be a .dll file_

can it remesh Particles into something meshy?

really i don't know @enzyme69: i'm testing the lib for now.

@zeffii
Copy link
Collaborator

zeffii commented Apr 21, 2017

@scorpion451 i suspect the problem could also be a mismatch between python 3.5 and your 3.6

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 21, 2017

TorusIso

pymcubes_torus

"""
in bounds s d=10 n=2
in iso_val s d=8.0 n=2
in samples s d=100 n=2
in r_i s d=5.0 n=2
in r_o s d=1.0 n=2
out vertices v
out triangles s
"""


import numpy as np
import sys
mcubes_path = r"/usr/local/lib/python3.5/dist-packages" #it depend on your OS but just paste the path where is mcubes
if not mcubes_path in sys.path:
    sys.path.append(mcubes_path)    
import mcubes
import math

# Create the volume
def f(x, y, z):
    
    # (sqrt(x*x+y*y)-3)^2+z*z-1 formula from MathMod
    res=(math.sqrt(x*x+y*y)-r_i)**2+z*z-r_o

    return res

# Extract the 16-isosurface

verts, tri = mcubes.marching_cubes_func(
    (-bounds, -bounds, -bounds), (bounds, bounds, bounds),  # Bounds
    samples, samples, samples,              # Number of samples in each dimension
    f,                          # Implicit function
    iso_val)                         # Isosurface value

vertices, triangles = [verts.tolist()], [tri.tolist()]

https://github.com/kalwalt/sverchok_nodes_collection/blob/master/scripts/pymcubes/torus_iso.py

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 21, 2017

Testing the scikit marching_cubes function:
ellipsoid_skimage_test
Example taken from here:
http://scikit-image.org/docs/dev/auto_examples/edges/plot_marching_cubes.html
Skimage marching cubes documentation:
http://scikit-image.org/docs/dev/api/skimage.measure.html#marching-cubes
The script i used:

"""
in sp s d=0.0 n=2
in iso_val s d=0.0 n=2
in step s d=1 n=2
in a s d=6 n=2
in b s d=10 n=2
in c s d=16 n=2
out vertices v
out faces s
"""


import numpy as np
import sys
scikit_path = r"/usr/local/lib/python3.5/dist-packages" # it depend on your OS but just paste the path where is scikit
if not scikit_path in sys.path:
    sys.path.append(scikit_path)
from skimage import measure
from skimage.draw import ellipsoid


# Generate a level set about zero of two identical ellipsoids in 3D
ellip_base = ellipsoid(a, b, c, levelset=True)
ellip_double = np.concatenate((ellip_base[:-1, ...],
                               ellip_base[2:, ...]), axis=0)

# Use marching cubes to obtain the surface mesh of these ellipsoids
verts, faces, normals, values = measure.marching_cubes(
    ellip_double, level=iso_val,spacing=(sp, sp, sp), step_size=step)

vertices, faces = [verts.tolist()], [faces.tolist()]

https://github.com/kalwalt/sverchok_nodes_collection/blob/master/scripts/skimage/ellipsoid_skimage.py

@kalwalt kalwalt changed the title pymcubes and sverchok Marching_cubes with pymcubes, skimage and sverchok Apr 21, 2017
@scorpion451
Copy link

scorpion451 commented Apr 21, 2017

@kalwalt double checked, and I do have mcubes in my C:\Program Files\Python36\Lib\site-packages folder, with

exporter.py
__init__.py
_mcubes.cp36-win_amd64.pyd # .pyd is theoretically a "better dll" format for windows python

I just updated Python, so I'm going to try rolling back to 3.5.2, see if that makes any difference.
EDIT: Turns out blender had been launching using my old python install because the update didn't change the path properly. Problem maybe solved.

@scorpion451
Copy link

scorpion451 commented Apr 21, 2017

Okay, so now that I've got it working and played with it for a while:
How can we make f = (interpolation/lerp/closest vertex/etc of an existing mesh)?
Add that and a quadder to this, and I am seeing the holy grail of retopo tools here.

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 21, 2017

Okay, so now that I've got it working and played with it for a while:

@scorpion451 Happy, that you got it working!

How can we make f = (interpolation/lerp/closest vertex/etc of an existing mesh)?

This is sure possible. Probably given the Bounding Box of the mesh you can calculate the distance of every vertex from the center of the BB, so finding the values for the marching cubes algorithm. This is a feature that would fine have with Sverchok. but for now we can only develop some script or macro, because pymcubes can't be installed in blender python. I suggest also to try the scikit-image module as mentioned in a previous post in this issue. For now I'm testing the two modules to see what is more convenient to use.

@nortikin
Copy link
Owner

nortikin commented Apr 22, 2017

Unexpected error: <class 'ImportError'>
on line:  2
Traceback (most recent call last):
  File "/home/ololo/.config/blender/2.78/scripts/addons/sverchok/nodes/generator/script1_lite.py", line 348, in process_script
    exec(self.script_str, locals(), locals())
  File "<string>", line 16, in <module>
ImportError: No module named 'mcubes._mcubes'
mcubes_path = r"/usr/lib/python3.6/site-packages/" #it depend on your OS but just paste the path where is scipy
if not mcubes_path in sys.path:
    sys.path.append(mcubes_path)    
import mcubes

the same 3.6

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 22, 2017

@nortikin i think should match the python versions. Blender use python 3.5 (at least 2.78a) your system python installed is as i can see 3.6.

@nortikin
Copy link
Owner

the same 3.6 problem, i see

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 22, 2017

if you can you should install python 3.5 on your system and after the pymcubes module

@nortikin
Copy link
Owner

Traceback (most recent call last):
  File "/home/ololo/.config/blender/2.78/scripts/addons/sverchok/nodes/generator/script1_lite.py", line 348, in process_script
    exec(self.script_str, locals(), locals())
  File "<string>", line 16, in <module>
ImportError: No module named 'mcubes._mcubes'

have now 3.5

@nortikin
Copy link
Owner

how to point blender on locan python?

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 22, 2017

@nortikin now how is your mcubes_path?

@nortikin
Copy link
Owner

nortikin commented Apr 22, 2017

@kalwalt r"/usr/lib/python3.5/site-packages/mcubes/"

@nortikin
Copy link
Owner

nortikin commented Apr 22, 2017

  File "/usr/lib/python3.5/site-packages/mcubes/__init__.py", line 2, in <module>
    from ._mcubes import marching_cubes, marching_cubes_func
ImportError: No module named 'mcubes._mcubes'

from ._mcubes import marching_cubes, marching_cubes_func
from .exporter import export_mesh, export_obj
cannot see this file, only _mcubes.cpython-35m-x86_64-linux-gnu.so

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 22, 2017

try:

-r"/usr/lib/python3.5/site-packages/"
+r"/usr/lib/python3.5/site-packages"

@zeffii
Copy link
Collaborator

zeffii commented Apr 25, 2017

stick a plate of glass ontop of that and you got a coffee table.

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 25, 2017

try also;

# instead of multiplying
v = Z * u
# try yo add
v = Z + u

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 25, 2017

pymcubes_w_numpygrid_noise_64_02
I did this only changing:

-v = Z * u
+v = Z + u

and adjusting the isovalue, note the difference with the previous image.

@paulofalcao
Copy link

Cool stuff, if I also send normals / colors or others attributes per vertex, how can I use them in sverchok / blender ?

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 25, 2017

Cool stuff, if I also send normals / colors or others attributes per vertex

Hi @paulofalcao, no pymcubes can't send normals or other vertex informations. Polyvox lib has this feature but the python bindings unfortunately not. I would update the bindings to the latest but Polyvox, the original lib in C++, is heavily templated and i don't feel very comfortable with.

how can I use them in sverchok / blender ?

i think you can do what you want with it. You can apply other nodes, baking in the scene and use all the modifiers and other blender tools.

@paulofalcao
Copy link

paulofalcao commented Apr 25, 2017

i think you can do what you want with it. You can apply other nodes, baking in the scene and use all the modifiers and other blender tools.

Thanks, that's what I was trying to do with a simple example like this:

"""
in bounds s d=10 n=2
in iso_val s d=0.0 n=2
in samples s d=100 n=2
in sphere_size s d=5.0 n=2
out vertices v
out triangles s
out normals v
out colors v
"""


import numpy as np
import sys
mcubes_path = r"/usr/local/lib/python3.6/site-packages/PyMCubes-0.0.6-py3.6-macosx-10.11-x86_64.egg"  # it depend on your OS but just paste the path where is mcubes
if not mcubes_path in sys.path:
    sys.path.append(mcubes_path)
import mcubes
import math


# Signed Distance Function
def sdf(x, y, z):
    x = x + math.sin(y*2.0)*1.0
    res = math.sqrt(x*x + y*y + z*z) - sphere_size
    return res

def norm(p):
    e = 0.001
    v = sdf(p[0],p[1],p[2])
    return np.linalg.norm([v-sdf(p[0]+e,p[1],p[2]),
                           v-sdf(p[0],p[1]+e,p[2]),
                           v-sdf(p[0],p[1],p[2]+e)])

def cor(p):
    return [math.sin(p[0]*0.5)+0.5,
            math.sin(p[1]*0.7)+0.5,
            math.sin(p[2]*0.9)+0.5]

# Extract the 16-isosurface
verts, tri = mcubes.marching_cubes_func(
    (-bounds, -bounds, -bounds), (bounds, bounds, bounds),  # Bounds
    samples, samples, samples,            # Number of samples in each dimension
    sdf,                                  # Signed Distance Function
    iso_val)                              # Isosurface value

vertices = [verts.tolist()]
triangles =  [tri.tolist()]
normals = map(norm,vertices)
colors = map(cor,vertices)

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 25, 2017

@paulofalcao great! but colors and normals i think won't works as it is now. Anyway you could plug into a viewer bmesh and a vertex color new to display the color information onto the mesh. But i will show you tomorrow, maybe opening another issue thread, as i have no time now

@paulofalcao
Copy link

@kalwalt, OK thanks. I was just playing around with these stuff :)

@nortikin
Copy link
Owner

consulted with pymcubes developer, i had blender 32 bit, system 64 bit, so it was not working )))

@kalwalt
Copy link
Contributor Author

kalwalt commented Apr 27, 2017

consulted with pymcubes developer, i had blender 32 bit, system 64 bit, so it was not working )))

Did you tried with blender 64 bit?

@nortikin
Copy link
Owner

yes, it importing ok

@enzyme69
Copy link
Collaborator

enzyme69 commented Apr 28, 2017 via email

@enzyme69
Copy link
Collaborator

enzyme69 commented Feb 6, 2018

With difficulty:

  • can install mcubes finally
  • numpy version was different, copy paste from outside into blender

Somewhat works:
screen shot 2018-02-06 at 11 04 49 pm

def heart(x,y,z):
    # some kind of heart 3D function
    
    res = 320 * ((-x**2 * z**3 -9*y**2 * z**3/80) + (x**2 + 9*y**2/4 + z**2-1)**3)
    return res

@zeffii
Copy link
Collaborator

zeffii commented Feb 6, 2018

also.. i can't get mcubes installed

if you want answers, paste / copy (not screenshot) the output of a working SNLite piped into a Debug node, and SNLite that doesn't work

and by "doesn't work" i mean, it doesn't display anything for VDMK. also show the whole Error messages, but maybe not the parts of the message that repeat, or have already been printed earlier.

@zeffii
Copy link
Collaborator

zeffii commented Feb 6, 2018

also.. disconnect the VDMK2 when you connect the debug print node

@enzyme69
Copy link
Collaborator

enzyme69 commented Feb 7, 2018

@zeffii Yes, I think the issue was: data list was empty: [[]] --> this gives "int not iterable" error. By adjusting parameter, etc, I finally got something.

False alarm.

something to do with this:
verts, tri = mcubes.marching_cubes(v, iso_val)

verts, tri = mcubes.marching_cubes(v, 0) --> empty list
verts, tri = mcubes.marching_cubes(v, 0.5) --> something appears!
verts, tri = mcubes.marching_cubes(v, 0.8) --> something appears!

I wish you can play with this "marching cube" stuff, interesting~

@enzyme69
Copy link
Collaborator

enzyme69 commented Feb 7, 2018

screen shot 2018-02-07 at 4 03 00 pm

@kalwalt
Copy link
Contributor Author

kalwalt commented Feb 7, 2018

hi @enzyme69 glad that you work with it ! pay attention to the iso values. As i remember it is very sensible. Sorry for my long delay here. I have no time to work or experimenting with sverchok and programming in general...

@nortikin
Copy link
Owner

clouds3
clouds2
clouds1

@nortikin
Copy link
Owner

nortikin commented Feb 12, 2018

clouds4
(y**2 / math.sin(z*y) + 2**x)**2

@nortikin
Copy link
Owner

@enzyme69
Copy link
Collaborator

enzyme69 commented Feb 12, 2018 via email

@akalyan3
Copy link

akalyan3 commented Apr 6, 2018

import mcubes command generating the following error:

Traceback (most recent call last):
File "<blender_console>", line 1, in
File "/Users/adityak/anaconda2/envs/conda-python-blender/lib/python3.5/site-packages/mcubes/init.py", line 2, in
from ._mcubes import marching_cubes, marching_cubes_func
ImportError: cannot import name 'marching_cubes'

Any help would be appreciated!

@enzyme69
Copy link
Collaborator

enzyme69 commented Apr 7, 2018

@akalyan3 You need to ensure that the module is callable from inside Blender or Script node.

Have you downloaded the PyMCubes module and install it into your computer and testing it using Python outside Blender? Ensuring also the Python version is good.

Then once it's good, you can call it using the lines mentioned above by @kalwalt

import sys
mcubes_path = r"/usr/local/lib/python3.5/dist-packages" #it depend on your OS but just paste the path where is mcubes
if not mcubes_path in sys.path:
    sys.path.append(mcubes_path)    
import mcubes

@akalyan3
Copy link

@enzyme69 Thanks for that. That resolved the issue. But I ran into another one :P
Traceback (most recent call last):
File "<blender_console>", line 1, in
File "/Users/adityak/anaconda2/envs/conda-python-blender/lib/python3.5/site-packages/mcubes/exporter.py", line 29, in export_mesh
vert_src = collada.source.FloatSource("verts-array", vertices, ('X','Y','Z'))
AttributeError: module 'collada' has no attribute 'source'

I'm trying to export a Schwarz.

@nortikin
Copy link
Owner

export? try other exporter from blender.
mcubes6
mcubes5
mcubes4
mcubes3
mcubes1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants