gp_toolbox/functions.py

351 lines
11 KiB
Python
Raw Normal View History

2021-01-10 16:47:17 +01:00
import bpy
from random import randint
from mathutils import Vector
from math import radians
from random import random as rand
import numpy as np
from bpy_extras.object_utils import world_to_camera_view as cam_space
import bmesh
from .utils import get_gp_draw_plane, link_vert,gp_stroke_to_bmesh,draw_gp_stroke,remapping
2021-01-10 16:47:17 +01:00
def to_bl_image(array, img):
2021-01-10 16:47:17 +01:00
# Write the result to Blender preview
width = len(array[0])
height = len(array)
image = bpy.data.images.get(img)
if not image :
image = bpy.data.images.new(img,width,height)
image.generated_width = width
image.generated_height = height
output_pixels = []
for y in range (0,height):
for x in range(0,width):
col = array[y][x]
if not isinstance(col,list) :
col = [col]*3
#print(col)
output_pixels.append(col[0])
output_pixels.append(col[1])
output_pixels.append(col[2])
output_pixels.append(1)
image.pixels = output_pixels
def bm_angle_split(bm, angle) :
2021-01-10 16:47:17 +01:00
bm.verts.ensure_lookup_table()
loop = link_vert(bm.verts[0],[bm.verts[0]])
splitted = []
verts_to_split = [v for v in loop if len(v.link_edges) == 2 and v.calc_edge_angle() > radians(angle)]
for i,v in enumerate(verts_to_split) :
split_verts = bmesh.utils.vert_separate(v, v.link_edges)
splitted.append(split_verts[0])
if i == 0 :
splitted.append(split_verts[1])
bm.verts.ensure_lookup_table()
if splitted :
loops = []
for v in splitted :
loop = link_vert(v,[v])
loops.append(loop)
else :
loops = [loop]
return loops
def bm_uniform_density(bm, cam, max_spacing):
2021-01-10 16:47:17 +01:00
from bpy_extras.object_utils import world_to_camera_view as cam_space
scene = bpy.context.scene
ratio = scene.render.resolution_y/scene.render.resolution_x
for edge in bm.edges[:] :
first = Vector(cam_space(scene,cam,edge.verts[0].co)[:-1])
last = Vector(cam_space(scene,cam,edge.verts[1].co)[:-1])
first[1]*= ratio
last[1]*= ratio
length = (last-first).length
#print(length)
if length > max_spacing :
bmesh.ops.subdivide_edges(bm, edges = [edge],cuts = round(length/max_spacing)-1)
return bm
def gp_stroke_angle_split (frame, strokes, angle):
2021-01-10 16:47:17 +01:00
strokes_info = gp_stroke_to_bmesh(strokes)
new_strokes = []
for stroke_info in strokes_info :
bm = stroke_info['bmesh']
palette = stroke_info['color']
line_width = stroke_info['line_width']
strength = bm.verts.layers.float['strength']
pressure = bm.verts.layers.float['pressure']
select = bm.verts.layers.int['select']
splitted_loops = bm_angle_split(bm,angle)
## FIXME: Should use -> drawing.remove_strokes(indices=(0,))
frame.drawing.strokes.remove(stroke_info['stroke'])
2021-01-10 16:47:17 +01:00
for loop in splitted_loops :
loop_info = [{'co':v.co,'strength': v[strength], 'pressure' :v[pressure],'select':v[select]} for v in loop]
new_stroke = draw_gp_stroke(loop_info,frame,palette,width = line_width)
new_strokes.append(new_stroke)
return new_strokes
def gp_stroke_uniform_density(cam, frame, strokes, max_spacing):
2021-01-10 16:47:17 +01:00
strokes_info = gp_stroke_to_bmesh(strokes)
new_strokes = []
for stroke_info in strokes_info :
bm = stroke_info['bmesh'].copy()
palette = stroke_info['color']
line_width = stroke_info['line_width']
strength = bm.verts.layers.float['strength']
pressure = bm.verts.layers.float['pressure']
select = bm.verts.layers.int['select']
bm_uniform_density(bm,cam,max_spacing)
## FIXME: Should use -> drawing.remove_strokes(indices=(0,))
2021-01-10 16:47:17 +01:00
frame.strokes.remove(stroke_info['stroke'])
bm.verts.ensure_lookup_table()
loop = link_vert(bm.verts[0],[bm.verts[0]])
loop_info = [{'co':v.co,'strength': v[strength], 'pressure' :v[pressure],'select':v[select]} for v in loop]
new_stroke = draw_gp_stroke(loop_info,frame,palette,width = line_width)
new_strokes.append(new_stroke)
return new_strokes
def along_stroke(stroke, attr, length, min, max) :
2021-01-10 16:47:17 +01:00
strokelen = len(stroke.points)
for index,point in enumerate(stroke.points) :
value = getattr(point,attr)
if index < length :
remap = remapping(index/length,0,1,min,max)
setattr(point,attr,value*remap)
if index > strokelen-length :
remap = remapping((strokelen-index)/length,0,1,min,max)
setattr(point,attr,value*remap)
def randomise_points(mat, points, attr, strength) :
2021-01-10 16:47:17 +01:00
for point in points :
if attr == 'co' :
2021-01-10 16:47:17 +01:00
random_x = (rand()-0.5)
random_y = (rand()-0.5)
x = (random_x*strength, 0.0, 0.0)
y = (0.0, random_y*strength, 0.0)
point.co+= mat * Vector(x) - mat.to_translation()
point.co+= mat * Vector(y) - mat.to_translation()
else :
value = getattr(point,attr)
random = (rand()-0.5)
setattr(point,attr,value+random*strength)
def zoom_to_object(cam, resolution, box, margin=0.01) :
2021-01-10 16:47:17 +01:00
min_x= box[0]
max_x= box[1]
min_y= box[2]
max_y= box[3]
ratio = resolution[0]/resolution[1]
zoom_cam = cam.copy()
zoom_cam.data = zoom_cam.data.copy()
center = ((max_x+min_x)/2,(max_y+min_y)/2)
factor = max((max_x-min_x),(max_y-min_y))+margin
zoom_cam.data.shift_x += (center[0]-0.5)/factor
zoom_cam.data.shift_y += (center[1]-0.5)/factor/ratio
zoom_cam.data.lens /= factor
bpy.context.scene.objects.link(zoom_cam)
resolution = (int(resolution[0]*factor), int(resolution[1]*factor))
2021-01-10 16:47:17 +01:00
scene = bpy.context.scene
res_x = scene.render.resolution_x
res_y =scene.render.resolution_y
scene.render.resolution_x = resolution[0]
scene.render.resolution_y = resolution[1]
frame = zoom_cam.data.view_frame(scene)
frame = [zoom_cam.matrix_world * corner for corner in frame]
modelview_matrix = zoom_cam.matrix_world.inverted().copy()
projection_matrix = zoom_cam.calc_matrix_camera(resolution[0],resolution[1],1,1).copy()
#bpy.data.cameras.remove(zoom_cam.data)
#bpy.data.objects.remove(zoom_cam)
#bpy.context.scene.objects.link(zoom_cam)
scene.render.resolution_x = res_x
scene.render.resolution_y = res_y
#print(matrix,resolution)
return modelview_matrix,projection_matrix,frame,resolution
# get object info
def get_object_info(mesh_groups, order_list = []) :
2021-01-10 16:47:17 +01:00
scene = bpy.context.scene
cam = scene.camera
#scale = scene.render.resolution_percentage / 100.0
res_x = int(scene.render.resolution_x)
res_y = int(scene.render.resolution_y)
scene.render.resolution_x = 1024
scene.render.resolution_y = 1024
cam_coord = cam.matrix_world.to_translation()
convert_table = {(255,255,255):-1,(0,0,0):0}
mesh_info = []
color_index = 1
for i,mesh_group in enumerate(mesh_groups) :
for ob in mesh_group["objects"] :
ob_info = {"object": ob, "materials" : [],"group_index" : i,'color_indexes':[]}
namespace = mesh_group['namespace']
ob_info['namespace'] = namespace
l_name = ob.name
if l_name.startswith(namespace+'_') :
l_name = namespace+'_'+'COLO_'+ob.name.split('_',1)[1]
else :
l_name = namespace+'_'+'COLO_'+l_name
ob_info['name'] = l_name
bm = bmesh.new()
bm.from_object(ob,scene)
ob_info["bm"] = bm
if not bm.verts : continue
ob_info["matrix"] = ob.matrix_world
if mesh_group.get("dupli_object") :
ob_info["matrix"] = mesh_group["dupli_object"].matrix_world * ob.matrix_world
global_bbox = [ob_info["matrix"] * Vector(v) for v in ob.bound_box]
global_bbox_center = Vector(np.mean(global_bbox,axis =0))
bbox_cam_space = [cam_space(scene,cam,p)[:-1] for p in global_bbox]
sorted_x = sorted(bbox_cam_space,key = lambda x : x[0])
sorted_y = sorted(bbox_cam_space,key = lambda x : x[1])
ob_info['box_2d']=[sorted_x[0][0],sorted_x[-1][0],sorted_y[0][1],sorted_y[-1][1]]
#print(ob_info['box_2d'])
'''
{
'x' : int(sorted_x[0][0]*res_x)-1,
'y' : int(sorted_y[0][1]*res_y)-1,
'width' : int(sorted_x[-1][0]*res_x - sorted_x[0][0]*res_x)+1,
'height' : int(sorted_y[-1][1]*res_y - sorted_y[0][1]*res_y)+1,
}
'''
#bbox_depth = [Vector(p - cam_coord).length for p in global_bbox]
#ob_info["depth"] = min(bbox_depth)
ob_info["depth"] = Vector(global_bbox_center - cam_coord).length
for slot in ob.material_slots :
mat = slot.material
mat_info = {'index' : color_index}
if mat :
color = [pow(v,1/2.2) for v in mat.diffuse_color]
name = mat.name
else :
color = [1,0,1]
name = "default"
#seed(i)
random_color = (randint(0,255),randint(0,255),randint(0,255))
if name.startswith(namespace+'_') :
name = namespace+'_'+'COLO_'+ name.split('_',1)[1]
else :
name = namespace+'_'+'COLO_'+name
mat_info["name"] = name
mat_info["color"] = color
mat_info["random_color"] = random_color
ob_info["materials"].append(mat_info)
ob_info["color_indexes"].append(color_index)
convert_table[random_color] = color_index
color_index +=1
if not ob.material_slots :
random_color = (randint(0,255),randint(0,255),randint(0,255))
ob_info["random_color"] = random_color
ob_info["color"] = (0.5,0.5,0.5)
ob_info["color_indexes"].append(color_index)
convert_table[random_color] = color_index
color_index +=1
mesh_info.append(ob_info)
mesh_info = sorted(mesh_info,key = lambda x : x['depth'],reverse=True)
#print("###")
#print([i['name'] for i in mesh_info])
if order_list :
for name in [i['name'] for i in mesh_info] :
if name not in order_list :
order_list.append(name)
mesh_info = sorted(mesh_info,key = lambda x : order_list.index(x['name']))
scene.render.resolution_x = res_x
scene.render.resolution_y = res_y
return mesh_info, convert_table
def redraw_ui() -> None:
"""Forces blender to redraw the UI."""
for screen in bpy.data.screens:
for area in screen.areas:
area.tag_redraw()