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$
  • $\begingroup$ How is tied not s duplicate of your other recent question? $\endgroup$ – someonewithpc Dec 16 '15 at 21:28
  • $\begingroup$ @someonewithpc, it is the same problem but I find two different solutions. It is not a duplicate $\endgroup$ – BetterEnglish Dec 16 '15 at 21:29
  • $\begingroup$ What is a binary matrix? Do you mean a separate file containing binary 3D data? $\endgroup$ – Christopher Janzon Dec 16 '15 at 23:22
  • 1
    $\begingroup$ I'm not sure I understand how this is different from your other question, can you elaborate? $\endgroup$ – Ray Mairlot Dec 17 '15 at 1:42
  • $\begingroup$ @ChristopherJanzon, Could you please explain how to pointInsideMesh(point,ob) work in your code? $\endgroup$ – BetterEnglish Dec 21 '15 at 17:01
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$
  • $\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$ – BetterEnglish Dec 17 '15 at 5:26
  • $\begingroup$ you can see my ansewer! $\endgroup$ – BetterEnglish Dec 17 '15 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$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.