4
$\begingroup$

I apply a Remesh modifier (Blocks) on a mesh and I want to generate a 3D binary matrix (voxelization) where each cell contains 0 (the cell does not belongs to the mesh) or 1 (the cells belongs to the mesh). enter image description here

$\endgroup$
6
  • $\begingroup$ How is tied not s duplicate of your other recent question? $\endgroup$ Commented Dec 16, 2015 at 21:28
  • $\begingroup$ @someonewithpc, it is the same problem but I find two different solutions. It is not a duplicate $\endgroup$ Commented Dec 16, 2015 at 21:29
  • $\begingroup$ What is a binary matrix? Do you mean a separate file containing binary 3D data? $\endgroup$ Commented Dec 16, 2015 at 23:22
  • 1
    $\begingroup$ I'm not sure I understand how this is different from your other question, can you elaborate? $\endgroup$ Commented Dec 17, 2015 at 1:42
  • $\begingroup$ @ChristopherJanzon, Could you please explain how to pointInsideMesh(point,ob) work in your code? $\endgroup$ Commented Dec 21, 2015 at 17:01

3 Answers 3

3
$\begingroup$

Alright, if I understood your question correctly, you want a lot of ones and zeros from a 3D mesh. Here's a script:

import bpy

object = bpy.data.objects['Suzanne']
radius = 2.0
resolution = 20
file = open("C:\\tmp\\out.txt", 'w')

import mathutils
from mathutils import Vector
def pointInsideMesh(point,ob):
 axes = [ mathutils.Vector((1,0,0)) ]
 outside = False
 for axis in axes:
    mat = ob.matrix_world
    mat.invert()
    orig = mat*point
    count = 0
    while True:
        location,normal,index = ob.ray_cast(orig,orig+axis*10000.0)
        if index == -1: break
        count += 1
        orig = location + axis*0.00001
    if count%2 == 0:
    outside = True
    break
return not outside

bla = radius/resolution

out = ""

for z in range(-resolution, resolution):
    for y in range(-resolution, resolution):
        for x in range(-resolution, resolution):
            loc = Vector((x*bla, y*bla, z*bla))
            print(loc)
            if(pointInsideMesh(loc, object) == True):
                out += '1'
            else:
                out += '0'
        out += '\n'
    out += '\n'
file.write(out)
file.close()

Again, I'm not fully sure this will answer your question, but I had fun making this script.

$\endgroup$
2
  • $\begingroup$ thanks for your answer. I need just to save the binary value in a 3D matrix like nump.zeros((dimx, dimy, dimz)) then, I save the matrix as ,csv file. $\endgroup$ Commented Dec 17, 2015 at 5:26
  • $\begingroup$ you can see my ansewer! $\endgroup$ Commented Dec 17, 2015 at 19:38
2
$\begingroup$

I changed the script so that it gets you a 3D numpy array, a 1D array, a CSV string and it writes that one to a file.

import bpy
import numpy as np
import mathutils
from mathutils import Vector

object = bpy.data.objects['Suzanne'] # Object
file = "C:\\tmp\\out.txt" # File output

resolution = 10 # Voxels per lengt unit
location = Vector((0.0,0.0,0.0)) # Center
size = Vector((1.0,1.0,1.0)) # Size


def pointInsideMesh(point,ob):
    axes = [ mathutils.Vector((1,0,0)) ]
    outside = False
    for axis in axes:
        mat = ob.matrix_world
        mat.invert()
        orig = mat*point
        count = 0
        while True:
            location,normal,index = ob.ray_cast(orig,orig+axis*10000.0)
            if index == -1: break
            count += 1
            orig = location + axis*0.00001
        if count%2 == 0:
            outside = True
            break
        return not outside

x_bla = int(size[0]/(1/resolution))
y_bla = int(size[1]/(1/resolution))
z_bla = int(size[2]/(1/resolution))

out=np.zeros((x_bla,y_bla,z_bla), dtype=np.int)

for z in range(-int(z_bla/2), int(z_bla/2)):
    for y in range(-int(y_bla/2), int(y_bla/2)):
        for x in range(-int(x_bla/2), int(x_bla/2)):
            loc = Vector((location[0]+(1/resolution)*x, location[1]+(1/resolution)*y, location[2]+(1/resolution)*z))
            if(pointInsideMesh(loc, object) == True):
                out[x][y][z] = 1

out_1D = np.empty((x_bla*y_bla*z_bla), dtype=int)
out_csv = ""

count = 0
for z in out:
    for y in z:
        for x in y:
            out_1D[count] = int(x)
            count+=1
for a in out_1D:
    out_csv += str(a)+","

print(out_csv)
out_file = open(file, "w")
out_file.write(out_csv)
out_file.close()

The way you use this script is changing 'Suzanne' in the top of the code with the name of the object you want to voxelize, change the rest of the parameters as you'd like and then do the following.

Choose screen layout Scripting, make a script and paste the script. With the script active, press Alt + P to run the script.

Blender v2.74 with Suzanne

Your CSV file should end up where specified.

C:\tmp\out.txt, Swedish OS

$\endgroup$
1
$\begingroup$

suppose that the object is located on (0,0,0) and we can put it in a 3D bounding box with defined by xmin,xmax, ymin,ymax and zmin zmax.

model

my code:

import bpy
import numpy as np
object = bpy.data.objects['modelPerson:Body']
#radius = 2.0
#resolution = 20
xmin=-1
xmax=1
ymin=-1
ymax=1
zmin=0
zmax=1.75;
size =.02# size of voxel 2cm*2cm*2cm
matrix=np.zeros((len(np.arange(xmin,xmax,size)),len(np.arange(ymin,ymax,size)),len(np.arange(zmin,zmax,size))))
import mathutils
from mathutils import Vector
def pointInsideMesh(point,ob):
 axes = [ mathutils.Vector((1,0,0)) ]
 outside = False
 for axis in axes:
    mat = ob.matrix_world
    mat.invert()
    orig = mat*point
    count = 0
    while True:
        location,normal,index = ob.ray_cast(orig,orig+axis*10000.0)
        if index == -1: break
        count += 1
        orig = location + axis*0.00001
    if count%2 == 0:
        outside = True
        break
 return not outside

bla = 1
i=-1
for x in np.arange(xmin, xmax,size):
    i=i+1
    j=-1
    for y in np.arange(ymin, ymax,size):
        j=j+1
        k=-1
        for z in np.arange(0, zmax,size):
            k=k+1
            loc = Vector((x*bla, y*bla, z*bla))
            print(loc)
            if(pointInsideMesh(loc, object) == True):
                matrix[i,j,k]=1
            else:
                matrix[i,j,k]=0
np.savetxt('matrix.csv', matrix.reshape(1,len(np.arange(xmin,xmax,size))*len(np.arange(ymin,ymax,size))*len(np.arange(zmin,zmax,size))),delimiter=',')        

voxelize

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .