Fen Dweller 4 лет назад
Родитель
Сommit
bf2e63f928
8 измененных файлов: 284 добавлений и 89 удалений
  1. +3
    -0
      scripts/blender/addons/.vscode/settings.json
  2. +0
    -26
      scripts/blender/addons/macrovision.py
  3. +33
    -0
      scripts/blender/addons/macrovision/__init__.py
  4. +79
    -32
      scripts/blender/addons/macrovision/ops.py
  5. +77
    -0
      scripts/blender/addons/macrovision/props.py
  6. +92
    -0
      scripts/blender/addons/macrovision/ui.py
  7. +0
    -0
      scripts/blender/addons/mv/__init__.py
  8. +0
    -31
      scripts/blender/addons/mv/ui.py

+ 3
- 0
scripts/blender/addons/.vscode/settings.json Просмотреть файл

@@ -0,0 +1,3 @@
{
"python.formatting.provider": "black"
}

+ 0
- 26
scripts/blender/addons/macrovision.py Просмотреть файл

@@ -1,26 +0,0 @@
import mv.ui
import mv.ops

import bpy
import importlib

bl_info = {
"name": "Macrovision",
"blender": (3, 0, 0),
"category": "Import-Export"
}


def register():
importlib.reload(mv.ui)
importlib.reload(mv.ops)
cls_lists = [mv.ops.clses, mv.ui.clses]
for cls_list in cls_lists:
for cls in cls_list:
bpy.utils.register_class(cls)

def unregister():
cls_lists = [mv.ops.clses, mv.ui.clses][::-1]
for cls_list in cls_lists[::-1]:
for cls in cls_list:
bpy.utils.register_class(cls)

+ 33
- 0
scripts/blender/addons/macrovision/__init__.py Просмотреть файл

@@ -0,0 +1,33 @@
from macrovision import ui, ops, props

import bpy
import importlib

bl_info = {
"name": "Macrovision",
"blender": (3, 0, 0),
"category": "Import-Export"
}

def register():
importlib.reload(ui)
importlib.reload(ops)
importlib.reload(props)
cls_lists = [props.clses, ops.clses, ui.clses]
for cls_list in cls_lists:
for cls in cls_list:
bpy.utils.register_class(cls)
for id, prop in props.scene_props.items():
setattr(bpy.types.Scene, id, prop)

def unregister():
cls_lists = [props.clses, ops.clses, ui.clses][::-1]
for cls_list in cls_lists[::-1]:
for cls in cls_list:
bpy.utils.unregister_class(cls)

for id in props.scene_props:
if id in props.scene_props:
delattr(bpy.types.Scene, id)

scripts/blender/addons/mv/ops.py → scripts/blender/addons/macrovision/ops.py Просмотреть файл

@@ -1,20 +1,22 @@
import bpy import bpy

from mathutils import Vector, Euler, Color from mathutils import Vector, Euler, Color
import json import json
import pathlib import pathlib
import os import os
from math import pi from math import pi
import random


VIEW_DATA = { VIEW_DATA = {
"Front": [0, 1, 2, "Front"],
"Angled": [0.25, 1, 2, "Angled"],
"Corner": [0.5, 1, 2, "Corner"],
"Side": [1, 1, 2, "Side"],
"Back Angled": [1.5, 1, 2, "Back Angled"],
"Back": [2, 1, 2, "Back"],
"Top": [0, 0, 1, "Top"],
"Bottom": [0, 2, 1, "Bottom"],
"Bottom Flipped": [2, 2, 1, "Bottom Flipped"],
"FRONT": [0, 1, 2, "Front"],
"ANGLED": [0.25, 1, 2, "Angled"],
"CORNER": [0.5, 1, 2, "Corner"],
"SIDE": [1, 1, 2, "Side"],
"BACK_ANGLED": [1.5, 1, 2, "Back Angled"],
"BACK": [2, 1, 2, "Back"],
"TOP": [0, 0, 1, "Top"],
"BOTTOM": [0, 2, 1, "Bottom"],
"BOTTOM_FLIPPED": [2, 2, 1, "Bottom Flipped"],
} }


def get_bounds(objects): def get_bounds(objects):
@@ -46,10 +48,6 @@ class MVConfigCollection(bpy.types.Operator):
def execute(self, context: bpy.types.Context): def execute(self, context: bpy.types.Context):
coll = context.scene.collection.children[0] coll = context.scene.collection.children[0]
coll.name = "Macrovision" coll.name = "Macrovision"
coll["MVName"] = "Name"
coll["MVViews"] = "Front"
coll["MVKind"] = "objects"
coll["MVViewLabels"] = "Front: Front"


mats = [ mats = [
("light", 0, 0, 1), ("light", 0, 0, 1),
@@ -109,18 +107,61 @@ class MVConfigCollection(bpy.types.Operator):


bpy.ops.object.lineart_clear_all() bpy.ops.object.lineart_clear_all()


return {"FINISHED"}
return {'FINISHED'}

class MVAssignMaterials(bpy.types.Operator):
bl_idname = "mv.assign_materials"
bl_label = "Assign Materials"
def execute(self, context: bpy.types.Context):
mv = bpy.data.collections["Macrovision"]
collections = mv.children

for coll in collections:
for object in coll.objects:
if object.type != "MESH":
continue
for index in range(len(object.material_slots)):
if object.material_slots[index].material.name in ('light', 'medium', 'dark'):
continue
if context.scene.mv_material_mode == 'RANDOM':
choices = [
bpy.data.materials['light'],
bpy.data.materials['medium'],
bpy.data.materials['dark']
]

object.material_slots[index].material = random.choice(choices)

if context.scene.mv_material_mode == 'NAMES':
material = object.material_slots[index].material
light_choices = context.scene.mv_material_names_light.split(",")
medium_choices = context.scene.mv_material_names_medium.split(",")

chosen = None


for choice in light_choices:
if choice in material.name or choice in object.name:
chosen = bpy.data.materials['light']
break


for choice in medium_choices:
if choice in material.name or choice in object.name:
chosen = bpy.data.materials['medium']
break

if chosen is None:
chosen = bpy.data.materials['dark']

object.material_slots[index].material = chosen

return {'FINISHED'}


class MVExport(bpy.types.Operator): class MVExport(bpy.types.Operator):
bl_idname = "mv.export" bl_idname = "mv.export"
bl_label = "Export objects" bl_label = "Export objects"


@classmethod
def poll(cls, context: bpy.types.Context):
return True

def execute(self, context: bpy.types.Context): def execute(self, context: bpy.types.Context):
path_info = pathlib.Path(bpy.data.filepath).parent.joinpath("macrovision-directory.txt") path_info = pathlib.Path(bpy.data.filepath).parent.joinpath("macrovision-directory.txt")
config_path = pathlib.Path(open(path_info).read().strip()) config_path = pathlib.Path(open(path_info).read().strip())
@@ -150,20 +191,21 @@ class MVExport(bpy.types.Operator):


all_data = {} all_data = {}


all_data["name"] = mv["MVName"]
all_data["kind"] = mv["MVKind"]
all_data["name"] = context.scene.mv_name
all_data["kind"] = context.scene.mv_kind
all_data["forms"] = [] all_data["forms"] = []


default_views = [] default_views = []


for view in mv["MVViews"].split(","):
default_views.append(VIEW_DATA[view.strip()])

if "MVViewLabels" in mv:
for pair in mv["MVViewLabels"].split(","):
key, val = pair.split(":")
VIEW_DATA[key.strip()][3] = val.strip()

for view in context.scene.mv_views:
key = view.view
default_views.append([
VIEW_DATA[key][0],
VIEW_DATA[key][1],
VIEW_DATA[key][2],
view.name if view.name != "" else VIEW_DATA[key][3]
])
print(default_views)


workdir = pathlib.Path(parent_workdir).joinpath(all_data["name"]) workdir = pathlib.Path(parent_workdir).joinpath(all_data["name"])


@@ -212,15 +254,19 @@ class MVExport(bpy.types.Operator):
c.location += Vector([0, 0, size * 2]) @ rot c.location += Vector([0, 0, size * 2]) @ rot
c.data.clip_start = size / 4 c.data.clip_start = size / 4
c.data.clip_end = size * 8 c.data.clip_end = size * 8

scale_factor = (10 ** context.scene.mv_scale_factor)

height = dimensions[angles[2]] * scale_factor
data["views"].append({ data["views"].append({
"name": angles[3], "name": angles[3],
"height": dimensions[angles[2]]
"height": height
}) })


if "Volume" in coll: if "Volume" in coll:
data["views"][-1]["volume"] = coll["Volume"]
data["views"][-1]["volume"] = coll["Volume"] * (scale_factor ** 3)
if "Mass" in coll: if "Mass" in coll:
data["views"][-1]["mass"] = coll["Mass"]
data["views"][-1]["mass"] = coll["Mass"] * (scale_factor ** 3)


lineart.hide_render = False lineart.hide_render = False
filename = f"{coll.name}-{angles[3]}.png" filename = f"{coll.name}-{angles[3]}.png"
@@ -237,9 +283,10 @@ class MVExport(bpy.types.Operator):
with open(workdir.joinpath("data.json"), "w") as file: with open(workdir.joinpath("data.json"), "w") as file:
json.dump(all_data, file) json.dump(all_data, file)


return {"FINISHED"}
return {'FINISHED'}


clses = [ clses = [
MVExport, MVExport,
MVAssignMaterials,
MVConfigCollection MVConfigCollection
] ]

+ 77
- 0
scripts/blender/addons/macrovision/props.py Просмотреть файл

@@ -0,0 +1,77 @@
import bpy

scene_props = {}

scene_props["mv_name"] = bpy.props.StringProperty(
name = "Name",
description = "The name of the thing",
default = ""
)

scene_props["mv_kind"] = bpy.props.StringProperty(
name = "Kind",
description = "What category the entity belongs to",
default = "objects"
)

class MVView(bpy.types.PropertyGroup):
view: bpy.props.EnumProperty(
name = "View",
description = "The angle to view from",
items = (
("FRONT", "Front", ""),
("ANGLED", "Angled", ""),
("CORNER", "Corner", ""),
("SIDE", "Side", ""),
("BACK", "Back", ""),
("TOP", "Top", ""),
("BOTTOM", "Bottom", "")
)
)
name: bpy.props.StringProperty(name = "Name", description="What to call this view")

scene_props["mv_views"] = bpy.props.CollectionProperty(
name = "Views",
description = "The views to view the object from",
type = MVView
)

scene_props["mv_views_index"] = bpy.props.IntProperty(
name = "Views index",
description = "View list index"
)

scene_props["mv_scale_factor"] = bpy.props.IntProperty(
name = "Scale Factor",
description = "Scale lengths by 10^x",
min = -20,
max = 20,
soft_min = -20,
soft_max = 20,
default = 5
)

scene_props["mv_material_mode"] = bpy.props.EnumProperty(
name = "Material Mode",
description = "How to decide what to replace each material with",
items = (
('RANDOM', "Random", 'Randomly assign materials'),
('NAMES', "Names", 'Turn the specified names medium or light; the rest become dark')
),
)

scene_props["mv_material_names_light"] = bpy.props.StringProperty(
name = "Light Colors",
description = "Materials containing these words will become light",
default = ""
)

scene_props["mv_material_names_medium"] = bpy.props.StringProperty(
name = "Medium Colors",
description = "Materials containing these words will become medium",
default = ""
)

clses = [
MVView
]

+ 92
- 0
scripts/blender/addons/macrovision/ui.py Просмотреть файл

@@ -0,0 +1,92 @@
from macrovision import ops

import bpy

class MV_UL_ViewList(bpy.types.UIList):
def draw_item(self, context, layout: bpy.types.UILayout, data, item, icon, active_data, active_propname, index):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
layout.prop(item, "view", text="")
layout.prop(item, "name", text="")
elif self.layout_type in {'GRID'}:
layout.alignment = 'CENTER'
layout.label(text='', icon = 'OBJECT_DATAMODE')

class MV_Views_List_Add(bpy.types.Operator):
bl_idname = "mv.views_list_add"
bl_label = "Add view"

def execute(self, context: bpy.types.Context):
context.scene.mv_views.add()
return {'FINISHED'}

class MV_Views_List_Delete(bpy.types.Operator):
bl_idname = "mv.views_list_delete"
bl_label = "Delete view"

@classmethod
def poll(self, context: bpy.types.Context):
return context.scene.mv_views

def execute(self, context: bpy.types.Context):
lst = context.scene.mv_views
index = context.scene.mv_views_index

lst.remove(index)

index = max(0, index - 1)
index = min(index, len(lst) - 1)

context.scene.mv_views_index = index
return {'FINISHED'}
class MVPanel(bpy.types.Panel):
bl_idname="OBJECT_PT_MV_menu"
bl_label="Macrovision"
bl_space_type="VIEW_3D"
bl_region_type="UI"
bl_category = "Macrovision"

@classmethod
def poll(cls, context):
return True

def draw(self, context):
layout = self.layout

box = layout.box()
box.label(text="Setup")

op_props = box.operator("mv.config_collection")
op_props = box.operator("mv.assign_materials")

box.prop(context.scene, "mv_material_mode")

if context.scene.mv_material_mode == "NAMES":
box.prop(context.scene, "mv_material_names_light")
box.prop(context.scene, "mv_material_names_medium")

box = layout.box()
box.label(text="Execute")

op_props = box.operator("mv.export")

box.prop(context.scene, "mv_name")
box.prop(context.scene, "mv_kind")
box.template_list(
"MV_UL_ViewList",
"Views",
context.scene,
"mv_views",
context.scene,
"mv_views_index"
)
row = box.row()

row.operator("mv.views_list_add", text="+")
row.operator("mv.views_list_delete", text="-")
box.prop(context.scene, 'mv_scale_factor')
clses = [
MV_UL_ViewList,
MV_Views_List_Add,
MV_Views_List_Delete,
MVPanel
]

+ 0
- 0
scripts/blender/addons/mv/__init__.py Просмотреть файл


+ 0
- 31
scripts/blender/addons/mv/ui.py Просмотреть файл

@@ -1,31 +0,0 @@
import mv.ops

import bpy

class MVPanel(bpy.types.Panel):
bl_idname="OBJECT_PT_MV_menu"
bl_label="Macrovision"
bl_space_type="VIEW_3D"
bl_region_type="UI"
bl_category = "Macrovision"

@classmethod
def poll(cls, context):
return True

def draw(self, context):
layout = self.layout

box = layout.box()
box.label(text="Setup")

box.operator("mv.config_collection")

box = layout.box()
box.label(text="Execute")

box.operator("mv.export")

clses = [
MVPanel
]

Загрузка…
Отмена
Сохранить