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).
-
$\begingroup$ How is tied not s duplicate of your other recent question? $\endgroup$– someonewithpcCommented 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$– BetterEnglishCommented Dec 16, 2015 at 21:29
-
$\begingroup$ What is a binary matrix? Do you mean a separate file containing binary 3D data? $\endgroup$– Christopher JanzonCommented 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$– Ray MairlotCommented Dec 17, 2015 at 1:42
-
$\begingroup$ @ChristopherJanzon, Could you please explain how to pointInsideMesh(point,ob) work in your code? $\endgroup$– BetterEnglishCommented Dec 21, 2015 at 17:01
3 Answers
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.
-
$\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
-
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.
Your CSV file should end up where specified.
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.
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=',')