Last active
March 9, 2020 09:17
-
-
Save havchr/a9ab0bd413599928694736563801c633 to your computer and use it in GitHub Desktop.
Small tool to help set up texture projectors for quick block-outs in blender.
This file contains hidden or 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 bpy | |
import math | |
bl_info = { | |
"name": "Easy setup of UV Projection", | |
"blender": (2, 80, 0), | |
"category": "UV", | |
} | |
uvProjectorsCollectionName="UVProjectors" | |
defaultUVProjectorCollectionName="UVProjectorDefault" | |
projectorObjectName="UVProjector" | |
def addUVProjModifier(context): | |
#First add UVProject if not allready in modifiers | |
uvProjIndex = context.active_object.modifiers.find("UVProject") | |
if uvProjIndex == -1: | |
bpy.ops.object.modifier_add(type='UV_PROJECT') | |
uvProjIndex = context.active_object.modifiers.find("UVProject") | |
uvProj = context.active_object.modifiers[uvProjIndex] | |
return uvProj | |
def createOrFindUvProjectorsCollection(): | |
if uvProjectorsCollectionName not in bpy.data.collections: | |
uvProjectorsCollection = bpy.data.collections.new(name=uvProjectorsCollectionName) | |
bpy.context.scene.collection.children.link(uvProjectorsCollection) | |
else: | |
uvProjectorsCollection = bpy.data.collections[uvProjectorsCollectionName] | |
return uvProjectorsCollection | |
def setProjectorsForModifier(uvProjModifier,projectorDad): | |
if projectorDad is not None: | |
uvProjModifier.projector_count = len(projectorDad.children) | |
for index,obChild in enumerate(projectorDad.children): | |
uvProjModifier.projectors[index].object = obChild | |
def createProjectorSystem(name=projectorObjectName, | |
collectionName=defaultUVProjectorCollectionName, | |
distanceFromOrigo=10.0, | |
offset=(0.0,0.0,0.0)): | |
#create default projector | |
print("creating projector system " + name) | |
deg90InRads = math.radians(90.0) | |
projectorData = [ | |
((0.0 + offset[0],-distanceFromOrigo + offset[1],0.0 + offset[2]),(deg90InRads,0.0,deg90InRads*0.0),("Projector_Neg_Y")), #near to frontproject | |
((distanceFromOrigo + offset[0],0 + offset[1],0 + offset[2]),(deg90InRads,0,deg90InRads*1),("Projector_Pos_X")), #left projection | |
((0 + offset[0],distanceFromOrigo + offset[1],0 + offset[2]),(deg90InRads,0,deg90InRads*2),("Projector_Pos_Y")), # far to back projection | |
((-distanceFromOrigo + offset[0],0 + offset[1],0 + offset[2]),(deg90InRads,0,deg90InRads*3),("Projector_Neg_X")), #right projection | |
((0 + offset[0],0 + offset[1] ,-distanceFromOrigo + offset[2]),(deg90InRads*2.0,0,0),("Projector_Neg_Z")), #top down projection | |
((0 + offset[0],0 + offset[1],distanceFromOrigo + offset[2]),(deg90InRads*0.0,0,0),("Projector_Pos_Z")) #bottom up projection | |
] | |
projDefCollection = bpy.data.collections.new(name=collectionName) | |
bpy.context.scene.collection.children.link(projDefCollection) | |
bpy.ops.object.empty_add(type="CUBE",location=offset,radius=distanceFromOrigo*0.6) | |
bpy.context.active_object.name = name | |
projectorDad = bpy.context.active_object | |
projDefCollection.objects.link(bpy.context.active_object) | |
bpy.context.scene.collection.objects.unlink(bpy.context.active_object) | |
bpy.context.selected_objects.clear() | |
for data in projectorData: | |
bpy.ops.object.empty_add(type="ARROWS",location=data[0],rotation=data[1],radius=distanceFromOrigo*0.5) | |
projDefCollection.objects.link(bpy.context.active_object) | |
bpy.context.active_object.name = data[2] | |
bpy.context.scene.collection.objects.unlink(bpy.context.active_object) | |
bpy.context.active_object.select_set(state=True) | |
bpy.context.view_layer.objects.active = projectorDad | |
bpy.ops.object.parent_set(keep_transform=True) | |
return (projDefCollection,projectorDad) | |
class OBJECT_OT_texture_project_setup(bpy.types.Operator): | |
"""Tooltip""" | |
bl_idname = "object.texture_project_setup" | |
bl_label = "Texture Project default setup" | |
@classmethod | |
def poll(cls, context): | |
return True | |
canDo = True | |
if context.active_object is None: | |
canDo = False | |
elif context.active_object.type is not 'MESH': | |
canDo = False | |
elif context.mode is not 'OBJECT': | |
canDo = False | |
return canDo | |
def execute(self, context): | |
if context.mode != 'OBJECT': | |
self.report(type={'OPERATOR','WARNING','ERROR'},message='Context needs to be object mode for UV projector setup to work.') | |
return {"CANCELLED"} | |
uvProj = addUVProjModifier(context) | |
projectorContainer = None | |
for ob in context.selected_objects: | |
if ob != context.active_object: | |
projectorContainer = ob | |
break | |
for col in bpy.data.collections: | |
print(col) | |
print(bpy.data.collections) | |
uvProjectorsCollection = createOrFindUvProjectorsCollection() | |
if projectorContainer is None: | |
if defaultUVProjectorCollectionName not in uvProjectorsCollection.children: | |
uvProjector = createProjectorSystem() | |
uvDefaultProjectionCollection = uvProjector[0] | |
projectorContainer = uvProjector[1] | |
bpy.context.scene.collection.children.unlink(uvDefaultProjectionCollection) | |
uvProjectorsCollection.children.link(uvDefaultProjectionCollection) | |
else: | |
uvDefaultProjectionCollection = bpy.data.collections[defaultUVProjectorCollectionName] | |
projectorContainer = uvDefaultProjectionCollection.objects[0] | |
print(projectorContainer) | |
if projectorContainer is not None: | |
setProjectorsForModifier(uvProjModifier=uvProj,projectorDad=projectorContainer) | |
return {'FINISHED'} | |
class OBJECT_OT_texture_project_add_new(bpy.types.Operator): | |
"""Tooltip""" | |
bl_idname = "object.texture_project_add_new" | |
bl_label = "Texture Project add new custom" | |
@classmethod | |
def poll(cls, context): | |
return True | |
canDo = True | |
if context.active_object is None: | |
canDo = False | |
elif context.active_object.type is not 'MESH': | |
canDo = False | |
elif context.mode is not 'OBJECT': | |
canDo = False | |
return canDo | |
def execute(self, context): | |
if context.mode != 'OBJECT': | |
self.report(type={'OPERATOR','WARNING','ERROR'},message='Context needs to be object mode for UV projector setup to work.') | |
return {"CANCELLED"} | |
#First add UVProject if not allready in modifiers | |
uvProj = addUVProjModifier(context) | |
#create collection or find collection | |
uvProjectorsCollection = createOrFindUvProjectorsCollection() | |
collectionName=context.active_object.name + "_UVProjector" | |
#place the custom projector above the active | |
boundLoc = context.active_object.bound_box.data.location | |
boundDims = context.active_object.bound_box.data.dimensions | |
offset=(0.0 + boundLoc.x ,0.0 + boundLoc.y,0.0 + boundLoc.z + boundDims.z+3) | |
projectorSystem = createProjectorSystem(collectionName=collectionName,offset=offset) | |
bpy.context.scene.collection.children.unlink(projectorSystem[0]) | |
uvProjectorsCollection.children.link(projectorSystem[0]) | |
projectorContainer = projectorSystem[1] | |
if projectorContainer is not None: | |
setProjectorsForModifier(uvProjModifier=uvProj,projectorDad=projectorContainer) | |
return {'FINISHED'} | |
class OBJECT_OT_texture_project_init_from_selection(bpy.types.Operator): | |
"""Tooltip""" | |
bl_idname = "object.texture_project_init_from_selection" | |
bl_label = "init UV Project with children of selection" | |
@classmethod | |
def poll(cls, context): | |
return True | |
canDo = True | |
if context.active_object is None: | |
canDo = False | |
elif context.active_object.type is not 'MESH': | |
canDo = False | |
elif context.mode is not 'OBJECT': | |
canDo = False | |
return canDo | |
def execute(self, context): | |
if context.mode != 'OBJECT': | |
self.report(type={'OPERATOR','WARNING','ERROR'},message='Context needs to be object mode for UV projector setup to work.') | |
return {"CANCELLED"} | |
#First add UVProject if not allready in modifiers | |
uvProj = addUVProjModifier(context) | |
projectorContainer = None | |
for ob in context.selected_objects: | |
if ob is not context.active_object: | |
projectorContainer = ob | |
break | |
if projectorContainer is None: | |
self.report(type={'OPERATOR','WARNING','ERROR'},message='Select projectorDad then thing to add projector UV to - then use this operator') | |
return {"CANCELLED"} | |
setProjectorsForModifier(uvProjModifier=uvProj,projectorDad=projectorContainer) | |
return {'FINISHED'} | |
class OBJECT_MT_texture_project_setup_menu(bpy.types.Menu): | |
bl_idname = 'object.texture_project_setup_menu' | |
bl_label = 'Texture Project setup' | |
def draw(self, context): | |
layout = self.layout | |
layout.operator(OBJECT_OT_texture_project_setup.bl_idname) | |
layout.operator(OBJECT_OT_texture_project_add_new.bl_idname) | |
layout.operator(OBJECT_OT_texture_project_init_from_selection.bl_idname) | |
def menu_func(self, context): | |
self.layout.menu(OBJECT_MT_texture_project_setup_menu.bl_idname, icon='MESH_CUBE') | |
def register(): | |
bpy.utils.register_class(OBJECT_OT_texture_project_setup) | |
bpy.utils.register_class(OBJECT_OT_texture_project_add_new) | |
bpy.utils.register_class(OBJECT_OT_texture_project_init_from_selection) | |
bpy.utils.register_class(OBJECT_MT_texture_project_setup_menu) | |
bpy.types.VIEW3D_MT_object_context_menu.append(menu_func) | |
def unregister(): | |
bpy.utils.unregister_class(OBJECT_OT_texture_project_setup) | |
bpy.utils.unregister_class(OBJECT_OT_texture_project_add_new) | |
bpy.utils.unregister_class(OBJECT_OT_texture_project_init_from_selection) | |
bpy.utils.unregister_class(OBJECT_MT_texture_project_setup_menu) | |
bpy.types.VIEW3D_MT_object_context_menu.remove(menu_func) | |
if __name__ == "__main__": | |
register() | |
# test call | |
bpy.ops.object.texture_project_setup_operator() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Video here : https://photos.app.goo.gl/YiQwpGc97ZVH9uj58