Page MenuHome

add_mesh_mixmesh.py

add_mesh_mixmesh.py

# -*- coding: utf-8 -*-
# ##### BEGIN GPL LICENSE BLOCK #####
#
# Blender script - MixMesh - Random Interpolated new mesh data
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) Feb 2012 by John Michael Palmer
# All rights reserved.
#
# Contact: john53john@gmail.com
# Information: none yet ###
#
# The Original Code is: all of this file.
#
# Contributor(s): none yet.
#
# ##### END GPL LICENSE BLOCK #####
bl_info = {
"name": "MixMesh",
"author": "John Michael Palmer (jump)",
"version": (0, 0, 1),
"blender": (2, 6, 3),
"location": "",
"description": "Mix meshes to make new objects",
"warning": "",
"wiki_url": "",
"tracker_url": ""\
"",
"category": "Add Mesh"}
import bpy
import mathutils as mut
class MixMeshSettings(bpy.types.PropertyGroup):
nnew = bpy.props.IntProperty(description='number of new objects to create', default=1,min=1,max=200)
rowlength = bpy.props.IntProperty(description='Row Length of new objects group', default=4,min=1,max=200)
meshA = bpy.props.StringProperty(default='???')
meshB = bpy.props.StringProperty(default='???')
#withusers = bpy.props.BoolProperty(description='show meshes with more than 0 users', default=False)
newname = bpy.props.StringProperty(default='Mixed')
absterms = bpy.props.BoolProperty(description='Use Absolute values for terms', default=False)
vrand = bpy.props.FloatProperty(default=0.0,precision=3,description='Random Range for individual vertices', step=10)
rangecC = bpy.props.FloatProperty(description='range center, constant C', default=0.5, step=10)
rangecCrr = bpy.props.FloatProperty(description='constant C, Random Range', default=0.0, step=10)
rangecL = bpy.props.FloatVectorProperty(size = 3, description='Range Center, Linear coefficients for x,y and z', default=(0.0,0.0,0.0), step=10)
rangecLrr = bpy.props.FloatVectorProperty(size = 3, description='Linear coefficients. Random Range', default=(0.0,0.0,0.0), step=10)
rangecQa = bpy.props.FloatVectorProperty(size = 3, description='Range Center. Quadratic coefficients for x^2,y^2 and z^2', default=(0.0,0.0,0.0), step=10)
rangecQarr = bpy.props.FloatVectorProperty(size = 3, description='Quadratic coefficients for x^2,y^2 and z^2. Random Range', default=(0.0,0.0,0.0), step=10)
rangecQb = bpy.props.FloatVectorProperty(size = 3, description='Range Center. Quadratic coefficients for xy,xz and yz', default=(0.0,0.0,0.0), step=10)
rangecQbrr = bpy.props.FloatVectorProperty(size = 3, description='Quadratic coefficients for xy,xz and yz. Random Range', default=(0.0,0.0,0.0), step=10)
termsmeshfrac = bpy.props.FloatProperty(description='Fraction from mesh A to B to use for the x, y, and z terms for Range center calculation', default=0.5, step=10)
termscenter = bpy.props.EnumProperty(items = (('C','Mesh Centers','Mesh Center calculated using mesh A, B and Terms mesh fraction'),
('BoxMin','Bounding Boxes Minimum','Uses maximums of bounding boxes of meshes and Terms mesh fraction'),
('BoxMax','Bounding Boxes Maximum','Uses minimums of bounding boxes of meshes and Terms mesh fraction')),
description = 'Choice of origin for the terms', default='C')
normalizeterms = bpy.props.EnumProperty(items =(('none','None','Don\'t scale the terms'),
('Box','Bounding Box','Use the dimensions of the bounding box of the terms'),
('BoxMax','Bounding Box Maximum','Use the maximum of the bounding box of the terms'),
),
description = 'How to rescale the terms to calculate the new mesh', default='none') #('BFirst','Bounding Boxes first','Normalize each mesh first with bounding box dimensions')
panelview = bpy.props.BoolVectorProperty(size=2, default=(False,False))
class MixMeshPanel(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_idname = 'MixMpanel'
bl_label = 'MixMesh'
def draw(self, context):
ob = context.active_object
sm = context.scene.mixmesh
viewicon = ['RESTRICT_VIEW_ON','RESTRICT_VIEW_OFF']
lo = self.layout
col = lo.column()
col.prop_search(sm,'meshA',bpy.data,'meshes',icon='MESH_DATA',text='Mesh A')
col.prop_search(sm,'meshB',bpy.data,'meshes',icon='MESH_DATA',text='Mesh B')
col.prop(sm,'newname',text='New Name')
row = col.row(align = True)
row.prop(sm,'nnew',text='New Objects')
row.prop(sm,'rowlength',text='Row Length')
box = col.box()
colb = box.column()
colb.label('Range Center Coefficients')
colb2 = colb.column(align=True)
colb2.prop(sm,'rangecC',text='Constant')
colb2.prop(sm,'rangecCrr',text='Random')
row = colb2.row(align=True)
row.label('Linear Terms')
row.operator('mixmeshops.setpanelview',icon=viewicon[int(sm.panelview[0])],text="",emboss=False).pos=0
if(sm.panelview[0]):
row = colb2.row()
row.label('x')
row.label('y')
row.label('z')
row = colb2.row()
row.prop(sm,'rangecL',text='')
row = colb2.row()
row.prop(sm,'rangecLrr',text='')
row = colb2.row(align=True)
row.label('Quadratic Terms')
row.operator('mixmeshops.setpanelview',icon=viewicon[int(sm.panelview[1])],text="",emboss=False).pos=1
if(sm.panelview[1]):
row = colb2.row()
row.label('x^2')
row.label('y^2')
row.label('z^2')
row = colb2.row()
row.prop(sm,'rangecQa',text='')
row = colb2.row()
row.prop(sm,'rangecQarr',text='')
row = colb2.row()
row.label('xy')
row.label('xz')
row.label('yz')
row = colb2.row()
row.prop(sm,'rangecQb',text='')
row = colb2.row()
row.prop(sm,'rangecQbrr',text='')
colb.prop(sm,'normalizeterms',text='Normalize Terms')
colb.prop(sm,'termscenter',text='Terms Center')
row = colb.row(align = True)
row.prop(sm,'termsmeshfrac',text='Terms mesh at')
row.prop(sm,'absterms',text='Absolute Values')
row = col.row()
row.prop(sm,'vrand',text='Vertex Random')
row = col.row()
col.operator('mixmeshops.makeobjects', text='Make Objects')
@classmethod
def poll(cls, context):
inobjectmode = (bpy.context.mode == 'OBJECT')
#atleastoneobject = bpy.context.selected_objects != []
return (inobjectmode)
class MakeObjects(bpy.types.Operator):
bl_idname = 'mixmeshops.makeobjects'
bl_label = 'Union All Objects'
@classmethod
def poll(cls, context):
sm = context.scene.mixmesh
meshAok = sm.meshA in bpy.data.meshes.keys()
meshBok = sm.meshB in bpy.data.meshes.keys()
return meshAok and meshBok
def execute(self, context):
bd = bpy.data
sc = context.scene
sm = context.scene.mixmesh
cloc = sc.cursor_location #mut.Vector(sc.cursor_location) #I don't want to change the cursor_location later
startcloc = mut.Vector(cloc)
if sm.nnew > 1:
mixgroupname = newname("Mix_"+sm.newname,bd.groups.keys())
bpy.data.groups.new(mixgroupname)
mesha = bd.meshes[sm.meshA]
meshb = bd.meshes[sm.meshB]
meshav = mesha.vertices
meshbv = meshb.vertices
boboxa = boundingbox(mesha)
boboxb = boundingbox(meshb)
numverts = min(len(meshav),len(meshbv))
if sm.termscenter == "C":
shiftva = mut.Vector([0,0,0])
shiftvb = mut.Vector([0,0,0])
if sm.termscenter == "BoxMin":
shiftva = boboxa[0]
shiftvb = boboxb[0]
if sm.termscenter == "BoxMax":
shiftva = boboxa[1]
shiftvb = boboxb[1]
print("shiftva",shiftva)
# make a list of vertices for the mesh that will be used for the terms
vertturms = []
vertcalc = []
for vertn in range(numverts):
verta = meshav[vertn].co - shiftva
vertb = meshbv[vertn].co - shiftvb
vertrange = vertb - verta
vertc = verta + (vertrange * sm.termsmeshfrac)
vertturms.append(vertc)
vertcalc.append((verta,vertrange))
# Set the normalizing vector
if(sm.normalizeterms == 'Box'):
boboxt = boundingbox(vertturms)
normvec = boboxt[1] - boboxt[0]
elif(sm.normalizeterms == 'BoxMax'):
boboxt = boundingbox(vertturms)
normvec = boboxt[1]
else:
normvec = mut.Vector([1,1,1])
# now start making the new objects
colinrow = 0
bhight = 0
for objectn in range(sm.nnew):
colinrow += 1
meshc = mesha.copy()
meshcv = meshc.vertices
mixname = newname(sm.newname, bd.objects.keys() + bd.meshes.keys())
meshc.name = mixname
newob = bd.objects.new(mixname,meshc)
sc.objects.link(newob)
newob.location = cloc
if sm.nnew > 1:
sc.objects.active = newob
print('adding to ',mixgroupname)
bpy.ops.object.group_link(group=mixgroupname)
randall = mut.noise.random()
# calculate coefficients using center and random range
C = (mut.noise.random() * sm.rangecCrr) - (sm.rangecCrr / 2.0) + sm.rangecC
Lx,Ly,Lz = vector_times((mut.noise.random_unit_vector() / 2.0), sm.rangecLrr) + mut.Vector(sm.rangecL)
Qxx,Qyy,Qzz = vector_times((mut.noise.random_unit_vector() / 2.0), sm.rangecQarr) + mut.Vector(sm.rangecQa)
Qxy,Qxz,Qyz = vector_times((mut.noise.random_unit_vector() / 2.0), sm.rangecQbrr) + mut.Vector(sm.rangecQb)
for vertn in range(numverts):
x,y,z = vector_div(vertturms[vertn],normvec)
if(sm.absterms):
fposL = abs(Lx * x) + abs(Ly * y) + abs(Lz * z)
fposQa = abs(Qxx * x * x) + abs(Qyy * y * y) + abs(Qzz * z * z)
fposQb = abs(Qxy * x * y) + abs(Qxz * x * z) + abs(Qyz * y * z)
else:
fposL = (Lx * x) + (Ly * y) + (Lz * z)
fposQa = (Qxx * x * x) + (Qyy * y * y) + (Qzz * z * z)
fposQb = (Qxy * x * y) + (Qxz * x * z) + (Qyz * y * z)
fpos = fposQa + fposQb + fposL + C
randval = (mut.noise.random() - 0.5) * sm.vrand # random position for each vertex
fpos += randval
verta = vertcalc[vertn][0]
vertrange = vertcalc[vertn][1]
meshcv[vertn].co = verta + (vertrange * fpos)
print((x,y,z),fpos,meshcv[vertn].co)
boboxc = boundingbox(meshc)
bhight = max(boboxc[1][1] - boboxc[0][1],bhight)
if colinrow >= sm.rowlength:
cloc = mut.Vector([startcloc[0], cloc[1] + bhight ,cloc[2]])
colinrow = 0
bhight = 0
else:
bwidth = boboxc[1][0] - boboxc[0][0]
cloc[0] += bwidth
return {'FINISHED'}
class SetPanelView(bpy.types.Operator):
'''Adds a footnode to the active object'''
bl_idname = 'mixmeshops.setpanelview'
bl_label = 'Panel View Toggle'
pos = bpy.props.IntProperty(default=0)
def execute(self, context):
sm = context.scene.mixmesh
sm.panelview[self.pos] = not(sm.panelview[self.pos])
return {'FINISHED'}
def newname(prefix, thesenames):
numstart = 0
testname = prefix #+'%03d'%numstart
while testname in thesenames:
numstart += 1
testname = prefix+'%03d'%numstart
return testname
def boundingbox(meshin):
if(type(meshin) is bpy.types.Mesh):
vx = [v.co[0] for v in meshin.vertices]
vy = [v.co[1] for v in meshin.vertices]
vz = [v.co[2] for v in meshin.vertices]
elif(type(meshin) is list):
vx = [v[0] for v in meshin]
vy = [v[1] for v in meshin]
vz = [v[2] for v in meshin]
minv = mut.Vector([min(vx),min(vy),min(vz)])
maxv = mut.Vector([max(vx),max(vy),max(vz)])
return [minv,maxv]
def vector_times(v1,v2):
return mut.Vector([v1[0]*v2[0], v1[1]*v2[1],v1[2]*v2[2]])
def vector_div(v1,v2):
return mut.Vector([v1[0]/v2[0], v1[1]/v2[1],v1[2]/v2[2]])
def vector_add(v,n):
return mut.Vector([v[0]+n, v[1]+n, v[2]+n])
def vector_mean(v):
meanval = sum(v)/len(v)
return mut.Vector([meanval,meanval,meanval])
def register():
bpy.utils.register_module(__name__)
bpy.types.Scene.mixmesh = bpy.props.PointerProperty(type=MixMeshSettings)
def unregister():
bpy.utils.unregister_module(__name__)
bpy.types.Scene.mixmesh = bpy.props.PointerProperty(type=MixMeshSettings)
if __name__ == "__main__":
register()

File Metadata

Mime Type
text/x-python
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
60/d5/10cb5872937e5f167522ec4179c8

Event Timeline