Last active
July 10, 2019 23:47
-
-
Save patmo141/709f57e96885aa2ebb45c48501934c60 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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