gp_toolbox/functions.py

351 lines
11 KiB
Python

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
def to_bl_image(array, img):
# 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) :
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):
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):
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'])
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):
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,))
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) :
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) :
for point in points :
if attr == 'co' :
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) :
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))
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 = []) :
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()