Skip to content

Instantly share code, notes, and snippets.

@patmo141
Last active July 10, 2019 23:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save patmo141/709f57e96885aa2ebb45c48501934c60 to your computer and use it in GitHub Desktop.
Save patmo141/709f57e96885aa2ebb45c48501934c60 to your computer and use it in GitHub Desktop.
import math
import time
import bpy
import bmesh
from mathutils import Vector, Matrix
def dyntopo_remesh(ob, dyntopo_resolution):
#TODO, may try context override!
'''
uses dynamic topology detail flood fill
to homogenize and triangulate a mesh object
it is destructive
'''
c = bpy.context.copy()
bpy.context.scene.objects.active = ob
sel_state = ob.select
ob.select = True
bpy.ops.object.mode_set(mode = 'SCULPT')
if not ob.use_dynamic_topology_sculpting:
bpy.ops.sculpt.dynamic_topology_toggle()
#save these settings to put them back as they were
detail_type = bpy.context.scene.tool_settings.sculpt.detail_type_method
detail_res = bpy.context.scene.tool_settings.sculpt.constant_detail_resolution
bpy.context.scene.tool_settings.sculpt.detail_type_method = 'CONSTANT'
bpy.context.scene.tool_settings.sculpt.constant_detail_resolution = dyntopo_resolution
bpy.ops.sculpt.detail_flood_fill()
#put the settings back
bpy.context.scene.tool_settings.sculpt.detail_type_method = detail_type
bpy.context.scene.tool_settings.sculpt.constant_detail_resolution = detail_res
#put the context back
bpy.ops.object.mode_set(mode = c['mode'])
bpy.context.scene.objects.active = c['object']
ob.select = sel_state
def refractory_model(model, direction, offset):
mx = model.matrix_world
i_mx = mx.inverted()
view = i_mx.to_quaternion() * direction
start = time.time()
bme = bmesh.new()
bme.from_mesh(model.data)
bme.verts.ensure_lookup_table()
bme.edges.ensure_lookup_table()
bme.faces.ensure_lookup_table()
#find the lowest part of the mesh to add a base plane to.
lowest_vert = min(bme.verts[:], key = lambda x: x.co.dot(view))
lowest_point = lowest_vert.co
#find the undercut verts
undercut_verts = set()
for f in bme.faces:
if f.normal.dot(direction) < -.01:
undercut_verts.update([v for v in f.verts])
finish = time.time()
print('found undercuts in %f seconds' % (finish-start))
start = finish
print('there are %i undercuts verts' % len(undercut_verts))
#find the perimeter verts
perimeter_verts = set()
perimeter_faces = set()
for ed in bme.edges:
if len(ed.link_faces) == 1:
perimeter_verts.update([ed.verts[0], ed.verts[1]])
for v in ed.verts:
perimeter_faces.update([f for f in v.link_faces])
meta_data = bpy.data.metaballs.new('Reractory Meta')
meta_obj = bpy.data.objects.new('Refractory Meta', meta_data)
meta_data.resolution = .5
meta_data.render_resolution = .5
bpy.context.scene.objects.link(meta_obj)
scale = 1
max_blockout = 20
n_elements = 0
max_height = math.ceil(max_blockout/(.25 * offset))
for v in bme.verts:
#extrude a chain of balls down
co = v.co
height = (lowest_point - v.co).dot(-view)
if v in perimeter_verts:
N = min(math.ceil(height/(.25 * offset)), max_height)
for i in range(0,N):
n_elements += 1
mb = meta_data.elements.new(type = 'BALL')
mb.co = scale * (co - i * .25 * view)
mb.radius = offset
if v in undercut_verts:
N = min(math.ceil(height/(.25*offset)), max_height) #limit the blockout depth
for i in range(0,N):
n_elements += 1
mb = meta_data.elements.new(type = 'BALL')
mb.co = scale * (co - i * .25 * offset * view)
mb.radius = offset
if not (v in perimeter_verts or v in undercut_verts):
n_elements += 1
mb= meta_data.elements.new(type = 'BALL')
mb.co = scale * co
bme.free()
meta_obj.matrix_world = model.matrix_world
#meta_obj_d.matrix_world = L * R * S
finish = time.time()
print('added metaballs in %f seconds' % (finish-start))
start = finish
bpy.context.scene.update()
me = meta_obj.to_mesh(bpy.context.scene, apply_modifiers = True, settings = 'PREVIEW')
finish = time.time()
print('converted to mesh %f seconds' % (finish-start))
start = finish
if 'Refractory Model' in bpy.data.objects:
new_ob = bpy.data.objects.get('Refractory Model')
old_data = new_ob.data
new_ob.data = me
old_data.user_clear()
bpy.data.meshes.remove(old_data)
else:
new_ob = bpy.data.objects.new('Refractory Model', me)
bpy.context.scene.objects.link(new_ob)
new_ob.matrix_world = model.matrix_world
bpy.context.scene.objects.unlink(meta_obj)
bpy.data.objects.remove(meta_obj)
bpy.data.metaballs.remove(meta_data)
return new_ob
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment