Revision 1fdee286
plugin_blender/__init__.py | ||
---|---|---|
1 |
bl_info = { |
|
2 |
"author": "Jonas Diekmann", |
|
3 |
"name": "Marker Tracker Plugin", |
|
4 |
"description": "Tools for BA-Thesis", |
|
5 |
"warning": "", |
|
6 |
"version": (0, 11, 3), |
|
7 |
"blender": (2, 72, 0), |
|
8 |
"support": "TESTING", |
|
9 |
"category": "Add Mesh" |
|
10 |
} |
|
11 |
# Dies ist die Hauptdatei des Plugins |
|
12 |
# Sie wird geladen, wenn das Plugin geladen wird. |
|
13 |
# Normalerweise geschieht dies beim Start von Blender |
|
14 |
# Es ist aber auch möglich diese datei direkt zu laden. |
|
15 |
# Aufgabe dieser Datei ist es alle anderen teile des |
|
16 |
# Plugins nachzuladen. |
|
17 |
### Der untestehende Code (bis ###) basiert auf [3]. |
|
18 |
|
|
19 |
# Lädt die Dateien neu, wenn das Plugin aufgefrischt werden soll. |
|
20 |
if "bpy" in locals(): |
|
21 |
import imp |
|
22 |
if "view" in locals(): |
|
23 |
imp.reload(view) |
|
24 |
else: |
|
25 |
print("Datei view.py fehlt!"); |
|
26 |
if "adjust" in locals(): |
|
27 |
imp.reload(adjust) |
|
28 |
else: |
|
29 |
print("Datei adjust.py fehlt!"); |
|
30 |
if "controller" in locals(): |
|
31 |
imp.reload(controller) |
|
32 |
else: |
|
33 |
print("Datei controller.py fehlt!"); |
|
34 |
if "model" in locals(): |
|
35 |
imp.reload(model) |
|
36 |
else: |
|
37 |
print("Datei model.py fehlt!"); |
|
38 |
if "switch_texture" in locals(): |
|
39 |
imp.reload(switch_texture) |
|
40 |
else: |
|
41 |
print("Datei switch_texture.py fehlt!"); |
|
42 |
if "tools" in locals(): |
|
43 |
imp.reload(tools) |
|
44 |
else: |
|
45 |
print("Datei tools.py fehlt!"); |
|
46 |
print("Pakete aufgefrischt") |
|
47 |
else: |
|
48 |
# Importiert die übrigen Module, wenn das Plugin (oder eigentlich bpy) |
|
49 |
# noch nicht geladen war. |
|
50 |
from .view import GraphischeOberflaeche |
|
51 |
from .adjust import KameraJustieren, FormatEinstellen, EinheitenEinstellen |
|
52 |
from .controller import PositionenAusgeben, MarkerHinzufuegen, MarkerRandomisieren #,EulerwinkelAusgeben |
|
53 |
from .model import Plugineigenschaften |
|
54 |
from .switch import WechsleBibliothek, WechsleZuBART, WechsleZuALVAR |
|
55 |
from .tools import Import1, Import2 |
|
56 |
print("Pakete importiert") |
|
57 |
### |
|
58 |
|
|
59 |
import bpy |
|
60 |
|
|
61 |
# Registriert alle Klassen des Plugins |
|
62 |
def register(): |
|
63 |
bpy.utils.register_class(Plugineigenschaften) |
|
64 |
bpy.types.Scene.markerRender = bpy.props.PointerProperty(type=Plugineigenschaften) |
|
65 |
bpy.types.Object.marker_id = bpy.props.IntProperty(default=-1,min=-1) |
|
66 |
bpy.types.ImageTexture.library = bpy.props.StringProperty(name="library",default='BART',maxlen=100) |
|
67 |
bpy.types.ImageTexture.marker_id = bpy.props.IntProperty(default=-1,min=-1) |
|
68 |
bpy.utils.register_class(PositionenAusgeben) |
|
69 |
bpy.utils.register_class(MarkerHinzufuegen) |
|
70 |
#bpy.utils.register_class(EulerwinkelAusgeben) |
|
71 |
bpy.utils.register_class(MarkerRandomisieren) |
|
72 |
bpy.utils.register_class(WechsleBibliothek) |
|
73 |
bpy.utils.register_class(WechsleZuBART) |
|
74 |
bpy.utils.register_class(WechsleZuALVAR) |
|
75 |
bpy.utils.register_class(EinheitenEinstellen) |
|
76 |
bpy.utils.register_class(KameraJustieren) |
|
77 |
bpy.utils.register_class(FormatEinstellen) |
|
78 |
bpy.utils.register_class(GraphischeOberflaeche) |
|
79 |
bpy.utils.register_class(Import1) |
|
80 |
bpy.utils.register_class(Import2) |
|
81 |
|
|
82 |
# Macht die Registrierung aller Klassen des Plugins rückgängig. |
|
83 |
def unregister(): |
|
84 |
bpy.utils.unregister_class(Import2) |
|
85 |
bpy.utils.unregister_class(Import1) |
|
86 |
bpy.utils.unregister_class(GraphischeOberflaeche) |
|
87 |
bpy.utils.unregister_class(MarkerRandomisieren) |
|
88 |
bpy.utils.unregister_class(FormatEinstellen) |
|
89 |
bpy.utils.unregister_class(KameraJustieren) |
|
90 |
bpy.utils.unregister_class(EinheitenEinstellen) |
|
91 |
bpy.utils.unregister_class(WechsleZuALVAR) |
|
92 |
bpy.utils.unregister_class(WechsleZuBART) |
|
93 |
bpy.utils.unregister_class(WechsleBibliothek) |
|
94 |
#bpy.utils.unregister_class(EulerwinkelAusgeben) |
|
95 |
bpy.utils.unregister_class(MarkerHinzufuegen) |
|
96 |
bpy.utils.unregister_class(PositionenAusgeben) |
|
97 |
bpy.utils.unregister_class(Plugineigenschaften) |
|
98 |
|
|
99 |
# Dies ist der Einsprungspunkt, falls das Skript über |
|
100 |
# die entsprechende Schaltfläche in Blender ausgeführt wird. |
|
101 |
if __name__ == "__main__": |
|
102 |
register() |
|
103 |
|
|
104 |
# Quellen: |
|
105 |
# 0 API: http://www.blender.org/api/blender_python_api_2_72_release |
|
106 |
# 1 PYTHON kurz & gut: |
|
107 |
# 2 Quickstart: http://www.blender.org/api/blender_python_api_2_72_release/info_quickstart.html |
|
108 |
# 3 Multi-file packages: http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Multi-File_packages |
|
109 |
# |
|
110 |
# Tipp: Der Tooltip der meisten Felder nennt den Pfad der Eigenschaft. |
|
111 |
# Operatoren werden zudem im Infofenster protokolliert. |
|
112 |
# Dadurch kann man manchmal die gewünschten Aktionen über die GUI durchführen und die Befehle kopieren. (vgl. auch http://www.blender.org/api/blender_python_api_2_72_release/info_api_reference.html#copy-data-path) |
|
113 |
|
plugin_blender/adjust.py | ||
---|---|---|
1 |
import bpy |
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
|
|
9 |
|
|
10 |
class KameraJustieren(bpy.types.Operator): |
|
11 |
"""Stellt die Kamera auf die für die Kalibrierung verwendeten Werte ein """ |
|
12 |
bl_idname = "camera.adjust_camera" |
|
13 |
bl_label = "Kamera justieren" |
|
14 |
|
|
15 |
# Wird ausgeführt um zu testen, ob die Operation des Operators möglich ist. |
|
16 |
@classmethod |
|
17 |
def poll(cls, context): |
|
18 |
return (bpy.context.scene.markerRender.kameraDatenID in bpy.data.cameras.keys()) |
|
19 |
|
|
20 |
# Stellt die Kamera auf die für die Kalibrierung verwendeten Werte ein |
|
21 |
def execute(self, context): |
|
22 |
kameraID = bpy.context.scene.markerRender.kameraDatenID |
|
23 |
bpy.data.cameras[kameraID].angle_x = 0.8575560450553894 |
|
24 |
bpy.data.cameras[kameraID].angle_y = 0.5033799409866333 |
|
25 |
bpy.data.cameras[kameraID].clip_end = 20.0 |
|
26 |
bpy.data.cameras[kameraID].clip_start = 0.10000000149011612 |
|
27 |
bpy.data.cameras[kameraID].sensor_fit = 'AUTO' |
|
28 |
bpy.data.cameras[kameraID].sensor_height = 18.0 |
|
29 |
bpy.data.cameras[kameraID].sensor_width = 32.0 |
|
30 |
bpy.data.cameras[kameraID].shift_x = 0.0 |
|
31 |
bpy.data.cameras[kameraID].shift_y = 0.0 |
|
32 |
bpy.data.cameras[kameraID].dof_distance = 7.929999828338623 |
|
33 |
return {'FINISHED'} |
|
34 |
|
|
35 |
class EinheitenEinstellen(bpy.types.Operator): |
|
36 |
"""Stellt das Einheitensystem ein""" |
|
37 |
bl_idname = "scene.adjust_units" |
|
38 |
bl_label = "Einheiten einstellen" |
|
39 |
|
|
40 |
# Wird ausgeführt um zu testen, ob die Operation des Operators möglich ist. |
|
41 |
@classmethod |
|
42 |
def poll(cls, context): |
|
43 |
return True |
|
44 |
|
|
45 |
# Stellt das Einheitensystem ein |
|
46 |
def execute(self, context): |
|
47 |
bpy.context.scene.unit_settings.system = "METRIC" |
|
48 |
return {'FINISHED'} |
|
49 |
|
|
50 |
class FormatEinstellen(bpy.types.Operator): |
|
51 |
"""Stellt das Ausgabeformat ein (Auflösung, Dateiformat etc.)""" |
|
52 |
bl_idname = "render.adjust_dimensions" |
|
53 |
bl_label = "Format einstellen" |
|
54 |
|
|
55 |
# Wird ausgeführt um zu testen, ob die Operation des Operators möglich ist. |
|
56 |
@classmethod |
|
57 |
def poll(cls, context): |
|
58 |
return True |
|
59 |
|
|
60 |
# Stellt das Ausgabeformat ein (Auflösung, Dateiformat etc.) |
|
61 |
def execute(self, context): |
|
62 |
### Der folgende Codeabschnitt (bis zum nächsten ### ) wurde mit bpy.ops.render.preset_add() erzeugt |
|
63 |
szene = bpy.context.scene |
|
64 |
szene.render.field_order = 'EVEN_FIRST' |
|
65 |
szene.render.fps = 48 |
|
66 |
szene.render.fps_base = 1.0 |
|
67 |
szene.render.pixel_aspect_x = 1.0 |
|
68 |
szene.render.pixel_aspect_y = 1.0 |
|
69 |
szene.render.resolution_percentage = 100 |
|
70 |
szene.render.resolution_x = 1920 |
|
71 |
szene.render.resolution_y = 1080 |
|
72 |
szene.render.use_fields = False |
|
73 |
szene.render.use_fields_still = False |
|
74 |
### |
|
75 |
bpy.data.scenes['Scene'].render.image_settings.file_format = "JPEG" |
|
76 |
bpy.data.scenes['Scene'].render.image_settings.quality = 100 |
|
77 |
return {'FINISHED'} |
plugin_blender/controller.py | ||
---|---|---|
1 |
import bpy |
|
2 |
from math import sqrt |
|
3 |
import random |
|
4 |
|
|
5 |
|
|
6 |
|
|
7 |
|
|
8 |
class PositionenAusgeben(bpy.types.Operator): |
|
9 |
"""Gibt die Distanz, Orientierung und Position im Koordinatensystem der Kamera aus""" |
|
10 |
bl_idname = "print_object.position" |
|
11 |
bl_label = "Position ausgeben" |
|
12 |
|
|
13 |
# Wird ausgeführt um zu testen, ob die Operation des Operators möglich ist. |
|
14 |
@classmethod |
|
15 |
def poll(cls, context): |
|
16 |
return ((bpy.context.scene.markerRender.kameraID in bpy.context.scene.objects.keys()) and (bpy.context.scene.markerRender.markerID in bpy.context.scene.objects.keys() or bpy.context.scene.markerRender.markerID == "") and (bpy.context.scene.markerRender.dateipfad != "")) |
|
17 |
|
|
18 |
# Gibt die Distanz, Orientierung und Position im Koordinatensystem der Kamera aus |
|
19 |
def execute(self, context): |
|
20 |
model = bpy.context.scene.markerRender |
|
21 |
dateipfad = bpy.path.abspath(model.dateipfad) |
|
22 |
ausgabedatei= open(bpy.path.ensure_ext(dateipfad,".txt"),mode='w') |
|
23 |
csvAusgabe= open(bpy.path.ensure_ext(dateipfad,".csv"),mode='w') |
|
24 |
bildnummer = 0 |
|
25 |
bpy.context.scene.frame_current = bpy.context.scene.frame_start |
|
26 |
while(bildnummer <= (bpy.context.scene.frame_end/bpy.context.scene.frame_step)): |
|
27 |
bpy.context.scene.frame_set(bpy.context.scene.frame_start + bildnummer * bpy.context.scene.frame_step) |
|
28 |
self.bildVerarbeiten(context,csvAusgabe,ausgabedatei,(bildnummer+1)) |
|
29 |
bildnummer += 1 |
|
30 |
ausgabedatei.flush() |
|
31 |
ausgabedatei.close() |
|
32 |
csvAusgabe.flush() |
|
33 |
csvAusgabe.close() |
|
34 |
print("Positionen nach",bpy.path.ensure_ext(dateipfad,".txt"),"und",bpy.path.ensure_ext(dateipfad,".csv"),"ausgegeben") |
|
35 |
return {'FINISHED'} |
|
36 |
|
|
37 |
# Wird für jedes Bild einmal ausgeführt |
|
38 |
def bildVerarbeiten(self, context, csvAusgabe, ausgabedatei, bildnummer): |
|
39 |
model = bpy.context.scene.markerRender |
|
40 |
kamera = context.scene.objects[model.kameraID] |
|
41 |
|
|
42 |
print("Bild",(bildnummer-1),file=ausgabedatei) |
|
43 |
print(" Kamera Position: (",end="",file=ausgabedatei) |
|
44 |
print(kamera.location.x, kamera.location.y, kamera.location.z,sep=",",end="",file=ausgabedatei) |
|
45 |
print(")",file=ausgabedatei) |
|
46 |
|
|
47 |
if(model.markerID == ""): |
|
48 |
zaehler = 0 |
|
49 |
zuEntfernen = [] |
|
50 |
for id in model.markerIDs: |
|
51 |
if(id.value in context.scene.objects.keys()): |
|
52 |
object = context.scene.objects[id.value] |
|
53 |
if(not object.hide_render): |
|
54 |
self.markerVerarbeiten(object,kamera,ausgabedatei,csvAusgabe,model,bildnummer) |
|
55 |
zaehler += 1 |
|
56 |
else: |
|
57 |
print("INFO: Vermisse "+id.value+" in "+str(context.scene.objects.keys())) |
|
58 |
zuEntfernen.append(zaehler) |
|
59 |
# Überflüssige Schlüssel entfernen |
|
60 |
for schluessel in zuEntfernen: |
|
61 |
model.markerIDs.remove(schluessel) |
|
62 |
else: |
|
63 |
object = context.scene.objects[model.markerID] |
|
64 |
self.markerVerarbeiten(object,kamera,ausgabedatei,csvAusgabe,model) |
|
65 |
|
|
66 |
def achsendatenAusgeben(self, dist,object,csvAusgabe): |
|
67 |
print(dist,sep=",",file=csvAusgabe) |
|
68 |
|
|
69 |
# wird für jeden Marker ausgeführt |
|
70 |
def markerVerarbeiten(self, object, kamera, ausgabedatei, csvAusgabe, model, bildnummer): |
|
71 |
dist = distanz(object.location.x,object.location.y,object.location.z,kamera.location.x,kamera.location.y,kamera.location.z) |
|
72 |
|
|
73 |
print(" ",object.name,"Position: (",end="",file=ausgabedatei) |
|
74 |
print(object.location.x, object.location.y, object.location.z,sep=",",end="",file=ausgabedatei) |
|
75 |
print(")",file=ausgabedatei) |
|
76 |
print(" ",object.name,"Distanz:",end=" ",file=ausgabedatei) |
|
77 |
print(dist,sep=",",file=ausgabedatei) |
|
78 |
|
|
79 |
#Testet, ob es einen einfachen Weg gibt an die Transformationsmatrix zwischen kamera und Objekt zu gelangen |
|
80 |
if(object.parent != None and object.parent == kamera): |
|
81 |
matrix = object.matrix_local |
|
82 |
elif(object.parent != None and object.parent.parent != None and object.parent.parent == kamera): |
|
83 |
matrix = object.parent.matrix_local*object.matrix_local |
|
84 |
else: |
|
85 |
#Es gibt keinen einfachen Weg :( |
|
86 |
print("Warnung: Invertierte globale Matritzen verwendet. Das ist weniger genau. Überlege, ob die Marker Kinder der Kamera oder eines ihrer direkten Kinder werden können.") |
|
87 |
print("Warnung: Invertierte globale Matritzen verwendet. Das ist weniger genau. Überlege, ob die Marker Kinder der Kamera oder eines ihrer direkten Kinder werden können.",file=ausgabedatei) |
|
88 |
matrix = kamera.matrix_world.inverted_safe()*object.matrix_world |
|
89 |
|
|
90 |
#An diesem Punkt enthält matrix die Transformationsmatrix zwischen Marker und Kamera |
|
91 |
|
|
92 |
# Gibt nach und nach die Bildnummer, die Markerid, die Rotationsmatrix, den Translationsvektor usw. aus |
|
93 |
if(matrix != None): |
|
94 |
print(" ",object.name,"Transformation bezüglich der Kamera:",file=ausgabedatei) |
|
95 |
if(object.marker_id != None): |
|
96 |
print(bildnummer,object.marker_id,sep=",",end=",",file=csvAusgabe) |
|
97 |
else: |
|
98 |
print(bildnummer,-1.0,sep=",",file=csvAusgabe) |
|
99 |
spalte = 0 |
|
100 |
while(spalte < len(matrix[0])): |
|
101 |
line = 0 |
|
102 |
print(" ",end="",file=ausgabedatei) |
|
103 |
while(line < len(matrix)): |
|
104 |
print(matrix[line][spalte],end=", ",file=ausgabedatei) |
|
105 |
if(not ((line%4) == 3)): |
|
106 |
print(matrix[line][spalte],end=",",file=csvAusgabe) |
|
107 |
line += 1 |
|
108 |
print("",file=ausgabedatei) |
|
109 |
spalte += 1 |
|
110 |
print("",file=ausgabedatei) |
|
111 |
print(matrix[3][3],end=",",file=csvAusgabe) |
|
112 |
self.achsendatenAusgeben(dist, object, csvAusgabe) |
|
113 |
|
|
114 |
|
|
115 |
#class EulerwinkelAusgeben(PositionenAusgeben): |
|
116 |
# """Gibt auch die Eulerwinkel für Achsenbeschriftungen aus""" |
|
117 |
# bl_idname = "print_object.rotation" |
|
118 |
# bl_label = "Include Rotation" |
|
119 |
# |
|
120 |
#def achsendatenAusgeben(self,dist,object,csvAusgabe): |
|
121 |
# euler = object.rotation_euler |
|
122 |
# print(dist,euler.x,euler.y,euler.z,sep=",",file=csvAusgabe) |
|
123 |
|
|
124 |
|
|
125 |
class MarkerHinzufuegen(bpy.types.Operator): |
|
126 |
"""Erzeugt ein neues flaches Objekt fügt es der Szene hinzu und versieht es mit entsprechenden Texturen und Attributen""" |
|
127 |
bl_idname = "mesh.primitive_marker_add" |
|
128 |
bl_label = "Marker hinzufügen" |
|
129 |
|
|
130 |
# Wird ausgeführt um zu testen, ob die Operation des Operators möglich ist. |
|
131 |
@classmethod |
|
132 |
def poll(cls, context): |
|
133 |
return context.mode == "OBJECT" |
|
134 |
|
|
135 |
# Wird ausgeführt, um einen neuen Marker hinzuzufügen |
|
136 |
def execute(self, context): |
|
137 |
markerID = str (bpy.context.scene.markerRender.newMarkerID) |
|
138 |
bpy.ops.object.select_all(action="DESELECT") |
|
139 |
|
|
140 |
markerIDSuffix = "" |
|
141 |
zaehler = 1 |
|
142 |
while("Marker_"+markerID+markerIDSuffix in bpy.data.objects.keys()): |
|
143 |
markerIDSuffix = ".0"+str (zaehler) |
|
144 |
zaehler += 1 |
|
145 |
|
|
146 |
#Erstellt Mesh |
|
147 |
bpy.ops.mesh.primitive_cube_add(radius=0.5) |
|
148 |
context.selected_objects[0].name = "Marker_"+markerID+markerIDSuffix |
|
149 |
bildschirm = context.screen |
|
150 |
gliederungGefunden = False |
|
151 |
for bereich in bildschirm.areas: |
|
152 |
if bereich.type == 'OUTLINER': |
|
153 |
gliederungGefunden = True |
|
154 |
kontextUeberschreiben = {'screen': bildschirm, 'area': bereich} |
|
155 |
bpy.ops.outliner.parent_drop(kontextUeberschreiben,child=context.selected_objects[0].name, parent=bpy.context.scene.markerRender.kameraID) |
|
156 |
break |
|
157 |
if(not gliederungGefunden): |
|
158 |
print("Skipped reparenting. Please activate Outliner!") |
|
159 |
|
|
160 |
context.selected_objects[0].scale[2] = 0.005 |
|
161 |
plane = context.selected_objects[0].data |
|
162 |
bpy.data.objects["Marker_"+markerID+markerIDSuffix].marker_id = bpy.context.scene.markerRender.newMarkerID |
|
163 |
|
|
164 |
#Erstellt Material |
|
165 |
bpy.ops.material.new() |
|
166 |
material = bpy.data.materials[-1] |
|
167 |
bpy.data.materials[-1].name = "Marker_"+markerID+markerIDSuffix |
|
168 |
|
|
169 |
|
|
170 |
#Erstellt Texturen |
|
171 |
material = createTexture(markerID,bpy.context.scene.markerRender.kontrastErhoehen,"//BART_Marker/","Marker","BART_Marker_",'BART',material) |
|
172 |
material = createTexture(markerID,bpy.context.scene.markerRender.kontrastErhoehen,"//ALVAR_Marker/","MarkerData_","ALVAR_Marker_",'ALVAR',material) |
|
173 |
|
|
174 |
#Weist Material zu |
|
175 |
plane.materials.append(material) |
|
176 |
|
|
177 |
#In Liste einhängen |
|
178 |
knoten = bpy.context.scene.markerRender.markerIDs.add() |
|
179 |
knoten.value = "Marker_"+markerID+markerIDSuffix |
|
180 |
|
|
181 |
#Unwrap (nur der obenliegenden Seite) |
|
182 |
bpy.ops.object.editmode_toggle() |
|
183 |
bpy.ops.mesh.select_all(action="DESELECT") |
|
184 |
bpy.ops.object.editmode_toggle() |
|
185 |
bpy.data.objects["Marker_"+markerID+markerIDSuffix].data.polygons[5].select = True |
|
186 |
bpy.ops.object.editmode_toggle() |
|
187 |
bpy.ops.uv.unwrap() |
|
188 |
bpy.ops.object.editmode_toggle() |
|
189 |
|
|
190 |
if(bpy.context.scene.markerRender.incrementNewMarkerID): |
|
191 |
bpy.context.scene.markerRender.newMarkerID+=1 |
|
192 |
return {'FINISHED'} |
|
193 |
|
|
194 |
class MarkerRandomisieren(bpy.types.Operator): |
|
195 |
"""Randomisiert die Markerid des ausgewählten Markers""" |
|
196 |
bl_idname = "mesh.randomize_marker" |
|
197 |
bl_label = "Marker randomisieren" |
|
198 |
|
|
199 |
# Wird ausgeführt um zu testen, ob die Operation des Operators möglich ist. |
|
200 |
@classmethod |
|
201 |
def poll(self,context): |
|
202 |
|
|
203 |
return True #context.object.marker_id > -1 |
|
204 |
|
|
205 |
def execute(self, context): |
|
206 |
ursprungsbild = context.scene.frame_current |
|
207 |
#Fange beim ersten Frame an |
|
208 |
context.scene.frame_current = 1 |
|
209 |
|
|
210 |
#Suche nach einem geeigneten Material |
|
211 |
object = context.object |
|
212 |
original_id = object.marker_id |
|
213 |
object.keyframe_insert("marker_id",frame=1) |
|
214 |
material_index = object.material_slots.find("Marker_"+str(original_id)) |
|
215 |
if(material_index == -1): |
|
216 |
# Die ID wurde leider verändert! Suche Material. |
|
217 |
# Da der Marker nur wenige Materialien enthalten dürften, sollte dieser Test schnell sein. |
|
218 |
material = None |
|
219 |
for material_slot in object.material_slots: |
|
220 |
for texture_slot in material_slot.material.texture_slots: |
|
221 |
if (texture_slot != None and texture_slot.texture.marker_id > -1): |
|
222 |
material = material_slot.material |
|
223 |
print("Warning: Using",material.name) |
|
224 |
break |
|
225 |
if(material == None): |
|
226 |
print("Could not randomise marker. Unable to find appropriate material.") |
|
227 |
return {'CANCELLED'} |
|
228 |
else: |
|
229 |
material = object.material_slots[material_index].material |
|
230 |
material.keyframe_insert("use_textures",options={'INSERTKEY_NEEDED'}) |
|
231 |
|
|
232 |
#Finde einen unbenutzten Slot |
|
233 |
material.active_texture_index = len(context.object.active_material.texture_slots.keys()) |
|
234 |
id = -1 |
|
235 |
usedids = [] |
|
236 |
while (context.scene.frame_current < context.scene.frame_end and material.active_texture_index < 17) : |
|
237 |
id = random.randint(original_id-50,original_id+50) |
|
238 |
if(id < 0): |
|
239 |
id += 50 |
|
240 |
elif(id > 1000): |
|
241 |
id %= 1000 |
|
242 |
|
|
243 |
if(id in usedids): |
|
244 |
#Die ids sollen einmalig sein, um die Streuung möglichst groß zu halten |
|
245 |
#und den Programmieraufwand beim Wechseln der Texturen zu verringern |
|
246 |
continue |
|
247 |
usedids.append(id) |
|
248 |
object.marker_id = id |
|
249 |
object.keyframe_insert("marker_id") |
|
250 |
#Workaround um zu verhindern, dass zwischen den IDs interpoliert wird |
|
251 |
object.keyframe_insert("marker_id",frame=context.scene.frame_current+1) |
|
252 |
object.keyframe_insert("marker_id",frame=context.scene.frame_current+2) |
|
253 |
object.keyframe_insert("marker_id",frame=context.scene.frame_current+3) |
|
254 |
|
|
255 |
#XXX Mit den Schlüsseln arbeiten, da Werte sonst nicht übernommen werden (keine reguläre Liste) |
|
256 |
for schluessel in range(0,len(material.use_textures)): |
|
257 |
material.use_textures[schluessel] = False |
|
258 |
|
|
259 |
# Die Textur für BART erstellen |
|
260 |
material = createTexture(str(id),False,"//BART_Marker/","Marker","BART_Marker_",'BART',material) |
|
261 |
material.use_textures[material.active_texture_index-1] = True |
|
262 |
|
|
263 |
# Die Textur für ALVAR erstellen |
|
264 |
material = createTexture(str(id),False,"//ALVAR_Marker/","MarkerData_","ALVAR_Marker_",'ALVAR',material) |
|
265 |
material.use_textures[material.active_texture_index-1] = True |
|
266 |
|
|
267 |
#Nach Erreichen von 17 wird nicht weiter hochgezählt, wir haben also erneut die Textur an Position 16 aktiviert und müssen das für 17 noch einmal erledigen. |
|
268 |
if(material.active_texture_index == 17): |
|
269 |
material.use_textures[17] = True |
|
270 |
material.keyframe_insert("use_textures",frame=context.scene.frame_current,options={'INSERTKEY_NEEDED'}) |
|
271 |
context.scene.frame_current += 4 |
|
272 |
print(id) |
|
273 |
|
|
274 |
#Mehr Texturen sind leider nicht erlaubt. Mische zwischen den vorhandenen Texturen. |
|
275 |
while(context.scene.frame_current < context.scene.frame_end): |
|
276 |
# Finde die Indizes für BART und erstelle ein Wörterbuch, das den Markernummern die Indizes von ALVAR zuordnet |
|
277 |
texturenBART = [ i for i in range(0,17) if material.texture_slots[i].texture.library == 'BART' and material.texture_slots[i].texture.marker_id != id] |
|
278 |
texturenALVAR = { material.texture_slots[i].texture.marker_id:i for i in range(0,17) if material.texture_slots[i].texture.library == 'ALVAR' and material.texture_slots[i].texture.marker_id != id} |
|
279 |
#Zufällige Reihenfolge herstellen |
|
280 |
random.shuffle(texturenBART) |
|
281 |
index = 0 |
|
282 |
while (context.scene.frame_current < context.scene.frame_end and index < len(texturenBART) and index < len(texturenALVAR)) : |
|
283 |
#XXX Mit den Schlüsseln arbeiten, da Werte sonst nicht übernommen werden (keine reguläre Liste) |
|
284 |
# Nicht benötigte Texturen deaktivieren |
|
285 |
for schluessel in range(0,len(material.use_textures)): |
|
286 |
material.use_textures[schluessel] = False |
|
287 |
slot_index = texturenBART[index] |
|
288 |
# Die ausgeloste Textur beider Bibliotheken aktivieren |
|
289 |
id = material.texture_slots[ slot_index ].texture.marker_id |
|
290 |
if(id in texturenALVAR): |
|
291 |
material.use_textures[ slot_index ] = True |
|
292 |
material.use_textures[ texturenALVAR[id] ] = True |
|
293 |
object.marker_id = id |
|
294 |
object.keyframe_insert("marker_id",frame=context.scene.frame_current) |
|
295 |
|
|
296 |
# Workaround um zu verhindern, dass zwischen den IDs der Schlüsselbilder Interpoliert wird |
|
297 |
object.keyframe_insert("marker_id",frame=context.scene.frame_current+1) |
|
298 |
object.keyframe_insert("marker_id",frame=context.scene.frame_current+2) |
|
299 |
object.keyframe_insert("marker_id",frame=context.scene.frame_current+3) |
|
300 |
material.keyframe_insert("use_textures",frame=context.scene.frame_current,options={'INSERTKEY_NEEDED'}) |
|
301 |
print(context.scene.frame_current,object.marker_id,material.texture_slots[ slot_index ].texture.name, material.texture_slots[ slot_index ].name) |
|
302 |
else: |
|
303 |
print("Warnung: Id",id,"wurde nicht für BART und ALVAR gefunden. Ich wähle eine andere.") |
|
304 |
index += 1 |
|
305 |
continue |
|
306 |
|
|
307 |
# Springe zum nächsten Schlüsselbild |
|
308 |
context.scene.frame_current += 4 |
|
309 |
index += 1 |
|
310 |
|
|
311 |
context.scene.frame_current = ursprungsbild |
|
312 |
return {'FINISHED'} |
|
313 |
|
|
314 |
|
|
315 |
# Hilfsfunktionen |
|
316 |
|
|
317 |
# Erzeugt eine Textur, für einen Marker mit der übergebenen markerID und den übergebenen Eigenschaften |
|
318 |
def createTexture(markerID,kontrastErhoehen,dateipfad,dateiPrefix,idPrefix,bibliotheksID,material): |
|
319 |
if(kontrastErhoehen): |
|
320 |
idSuffix = "hC" |
|
321 |
else: |
|
322 |
idSuffix = "" |
|
323 |
if(not (idPrefix+markerID+idSuffix in bpy.data.textures.keys())): |
|
324 |
# Erstellt Textur |
|
325 |
bpy.ops.texture.new() |
|
326 |
bpy.data.textures[-1].name = idPrefix+markerID+idSuffix |
|
327 |
bpy.data.textures[idPrefix+markerID+idSuffix].type = 'IMAGE' |
|
328 |
bpy.ops.image.open(filepath=dateipfad+dateiPrefix+markerID+".png") |
|
329 |
|
|
330 |
# Sorgt für eindeutige Identifikation, für den Fall das der Benutzer bzw. die Benutzerin Texturen und Bilder verschiebt und/oder umbenennt |
|
331 |
bpy.data.textures[idPrefix+markerID+idSuffix].library = bibliotheksID |
|
332 |
bpy.data.textures[idPrefix+markerID+idSuffix].marker_id = int(markerID) |
|
333 |
|
|
334 |
bpy.data.textures[idPrefix+markerID+idSuffix].image = bpy.data.images[dateiPrefix+markerID+".png"] |
|
335 |
if(kontrastErhoehen): |
|
336 |
# Erhöht den Kontrast |
|
337 |
bpy.data.textures[idPrefix+markerID+idSuffix].intensity = 2 |
|
338 |
bpy.data.textures[idPrefix+markerID+idSuffix].contrast = 3 |
|
339 |
|
|
340 |
# Weist die Standard-UV-Map zu |
|
341 |
material.active_texture = bpy.data.textures[idPrefix+markerID+idSuffix] |
|
342 |
material.texture_slots[material.active_texture_index].texture_coords = 'UV' |
|
343 |
material.texture_slots[material.active_texture_index].uv_layer = 'UVMap' |
|
344 |
material.active_texture_index+=1 |
|
345 |
return material |
|
346 |
|
|
347 |
# Berechnet den Abstand zweier Punkte 1 und 2 |
|
348 |
def distanz(x1,y1,z1,x2,y2,z2): |
|
349 |
return laenge(x1-x2,y1-y2,z1-z2) |
|
350 |
|
|
351 |
# Berechnet die Länge eines Vektors |
|
352 |
def laenge(x,y,z): |
|
353 |
return sqrt(x*x+y*y+z*z) |
|
354 |
|
plugin_blender/model.py | ||
---|---|---|
1 |
import bpy |
|
2 |
|
|
3 |
|
|
4 |
|
|
5 |
class Plugineigenschaften(bpy.types.PropertyGroup): |
|
6 |
"""Enthält die von diesem Plugin verwendeten Daten""" |
|
7 |
kameraID = bpy.props.StringProperty(name="kameraID",description="Die ID der zu verwendenden Kamera") |
|
8 |
kameraDatenID = bpy.props.StringProperty(name="kameraDatenID",description="Die ID des zu der Kamera gehörenden Datenblockes") |
|
9 |
markerID = bpy.props.StringProperty(name="markerID",description="Die (Blender-)ID des zu trackenden Markers. Bei einem leeren Feld werden alle Marker verwendet.") |
|
10 |
dateipfad = bpy.props.StringProperty(subtype="FILE_PATH") |
|
11 |
newMarkerID = bpy.props.IntProperty(min=0,soft_min=0,max=1000) |
|
12 |
incrementNewMarkerID = bpy.props.BoolProperty(description="Markernummer nach der Erzeugung erhöhen") |
|
13 |
kontrastErhoehen = bpy.props.BoolProperty(description="Kontrast und Helligkeit des Markers erhöhen") |
|
14 |
markerIDs = bpy.props.CollectionProperty(type=bpy.types.NodeSetting) |
|
15 |
|
plugin_blender/switch.py | ||
---|---|---|
1 |
import bpy |
|
2 |
|
|
3 |
class WechsleBibliothek(bpy.types.Operator): |
|
4 |
"""Oberklasse aller Klassen für Texturwechsel""" |
|
5 |
bl_idname = "texture.to_library" |
|
6 |
bl_label = "LIBRARY" |
|
7 |
|
|
8 |
# Wird ausgeführt um zu testen, ob die Operation des Operators möglich ist. |
|
9 |
@classmethod |
|
10 |
def poll(cls,context): |
|
11 |
return context.mode == "OBJECT" |
|
12 |
|
|
13 |
# Wird ausgeführt um die Textur zu wechseln |
|
14 |
def execute(self,context): |
|
15 |
model = bpy.context.scene.markerRender |
|
16 |
zaehler = 0 |
|
17 |
zuEntfernen = [] |
|
18 |
#Schleife über alle Marker |
|
19 |
for id in model.markerIDs: |
|
20 |
if(id.value in context.scene.objects.keys()): |
|
21 |
marker = context.scene.objects[id.value] |
|
22 |
self.markerVerarbeiten(context,marker,model) |
|
23 |
zaehler += 1 |
|
24 |
else: |
|
25 |
print("INFO: Missing "+id.value+" in "+str(context.scene.objects.keys())) |
|
26 |
zuEntfernen.append(zaehler) |
|
27 |
# Überflüssige Schlüssel entfernen |
|
28 |
for schluessel in zuEntfernen: |
|
29 |
model.markerIDs.remove(schluessel) |
|
30 |
return {'FINISHED'} |
|
31 |
|
|
32 |
# Platzhalter soll überschrieben werden |
|
33 |
def markerVerarbeiten(self,context,marker,model): |
|
34 |
#Texturen usw. packen |
|
35 |
bpy.ops.file.pack_all() |
|
36 |
print("pack_all") |
|
37 |
|
|
38 |
class WechsleZuBART(WechsleBibliothek): |
|
39 |
"""Aktiviert die Texturen von BART""" |
|
40 |
bl_idname = "texture.to_bart" |
|
41 |
bl_label = "BART" |
|
42 |
|
|
43 |
# Aktiviert die Textur von BART |
|
44 |
def markerVerarbeiten(self,context,marker,model): |
|
45 |
#Texturen usw. packen |
|
46 |
bpy.ops.file.pack_all() |
|
47 |
|
|
48 |
#Erstelle Wörterbücher, die einem Marker die id des Texturschachtes mit der entsprechenden Textur zuordnen |
|
49 |
texturenBART = { marker.material_slots[0].material.texture_slots[i].texture.marker_id:i for i in range(0,18) if marker.material_slots[0].material.texture_slots[i] != None and marker.material_slots[0].material.texture_slots[i].texture.library == 'BART'} |
|
50 |
texturenALVAR = { marker.material_slots[0].material.texture_slots[i].texture.marker_id:i for i in range(0,18) if marker.material_slots[0].material.texture_slots[i] != None and marker.material_slots[0].material.texture_slots[i].texture.library == 'ALVAR'} |
|
51 |
|
|
52 |
for bild in range(context.scene.frame_start,context.scene.frame_end): |
|
53 |
bpy.context.scene.frame_set(bild) |
|
54 |
#Die passende Textur von BART aktivieren |
|
55 |
for schluessel in texturenBART: |
|
56 |
if((schluessel in texturenALVAR and marker.material_slots[0].material.use_textures[texturenALVAR[schluessel]]) or marker.material_slots[0].material.use_textures[texturenBART[schluessel]]): |
|
57 |
print(bild,":",schluessel) |
|
58 |
marker.material_slots[0].material.use_textures[texturenBART[schluessel]] = True |
|
59 |
marker.material_slots[0].material.keyframe_insert("use_textures",index=texturenBART[schluessel],frame=bild,options={'INSERTKEY_NEEDED'}) |
|
60 |
#Die Textur von ALVAR ggf. deaktivieren |
|
61 |
for index in texturenALVAR: |
|
62 |
marker.material_slots[0].material.use_textures[texturenALVAR[index]] = False |
|
63 |
marker.material_slots[0].material.keyframe_insert("use_textures",index=texturenALVAR[index],frame=bild,options={'INSERTKEY_NEEDED'}) |
|
64 |
|
|
65 |
class WechsleZuALVAR(WechsleBibliothek): |
|
66 |
"""Aktiviert die Texturen von ALVAR""" |
|
67 |
bl_idname = "texture.to_alvar" |
|
68 |
bl_label = "ALVAR" |
|
69 |
|
|
70 |
# Aktiviert die Textur von ALVAR |
|
71 |
def markerVerarbeiten(self,context,marker,model): |
|
72 |
#Texturen usw. packen |
|
73 |
bpy.ops.file.pack_all() |
|
74 |
|
|
75 |
#Erstelle Wörterbücher, die einem Marker die id des Texturschachtes mit der entsprechenden Textur zuordnen |
|
76 |
texturenBART = { marker.material_slots[0].material.texture_slots[i].texture.marker_id:i for i in range(0,18) if marker.material_slots[0].material.texture_slots[i] != None and marker.material_slots[0].material.texture_slots[i].texture.library == 'BART'} |
|
77 |
texturenALVAR = { marker.material_slots[0].material.texture_slots[i].texture.marker_id:i for i in range(0,18) if marker.material_slots[0].material.texture_slots[i] != None and marker.material_slots[0].material.texture_slots[i].texture.library == 'ALVAR'} |
|
78 |
print("texturenBART",texturenBART) |
|
79 |
print("texturenALVAR",texturenALVAR) |
|
80 |
|
|
81 |
for bild in range(context.scene.frame_start,context.scene.frame_end): |
|
82 |
bpy.context.scene.frame_set(bild) |
|
83 |
|
|
84 |
#Die passende Textur von ALVAR aktivieren |
|
85 |
for schluessel in texturenALVAR: |
|
86 |
if((schluessel in texturenBART and marker.material_slots[0].material.use_textures[texturenBART[schluessel]]) or marker.material_slots[0].material.use_textures[texturenALVAR[schluessel]]): |
|
87 |
marker.material_slots[0].material.use_textures[texturenALVAR[schluessel]] = True |
|
88 |
marker.material_slots[0].material.keyframe_insert("use_textures",index=texturenALVAR[schluessel],frame=bild,options={'INSERTKEY_NEEDED'}) |
|
89 |
|
|
90 |
#Die Textur von BART ggf. deaktivieren |
|
91 |
for index in texturenBART: |
|
92 |
marker.material_slots[0].material.use_textures[texturenBART[index]] = False |
|
93 |
marker.material_slots[0].material.keyframe_insert("use_textures",index=texturenBART[index],frame=bild,options={'INSERTKEY_NEEDED'}) |
plugin_blender/tools.py | ||
---|---|---|
1 |
import bpy |
|
2 |
|
|
3 |
class Import1(bpy.types.Operator): |
|
4 |
"""Fügt evtl. fehlende Schlüssel hinzu""" |
|
5 |
bl_idname = "tools.import1" |
|
6 |
bl_label = "Import 1" |
|
7 |
|
|
8 |
# Wird ausgeführt um zu testen, ob die Operation des Operators möglich ist. |
|
9 |
@classmethod |
|
10 |
def poll(self, context): |
|
11 |
return True |
|
12 |
|
|
13 |
# Fügt evtl. fehlende Schlüssel hinzu |
|
14 |
def execute(self, context): |
|
15 |
#Ergänzt das Schlüsselattribut: |
|
16 |
for schluessel in bpy.data.objects.keys(): |
|
17 |
if (schluessel[-2] == '_'): |
|
18 |
print(schluessel) |
|
19 |
bpy.data.objects[schluessel].marker_id = int(schluessel[-1]) |
|
20 |
elif (schluessel[-3] == '_'): |
|
21 |
print(schluessel) |
|
22 |
bpy.data.objects[schluessel].marker_id = int(schluessel[-2:]) |
|
23 |
elif (schluessel[-4] == '_'): |
|
24 |
print(schluessel) |
|
25 |
bpy.data.objects[schluessel].marker_id = int(schluessel[-3:]) |
|
26 |
return{'FINISHED'} |
|
27 |
|
|
28 |
class Import2(bpy.types.Operator): |
|
29 |
"""Fügt neuere Schlüssel zu den Texturen hinzu""" |
|
30 |
bl_idname = "tools.import2" |
|
31 |
bl_label = "Import 2" |
|
32 |
|
|
33 |
# Wird ausgeführt um zu testen, ob die Operation des Operators möglich ist. |
|
34 |
@classmethod |
|
35 |
def poll(self, context): |
|
36 |
return True |
|
37 |
|
|
38 |
# Fügt neuere Schlüssel zu den Texturen hinzu |
|
39 |
def execute(self, context): |
|
40 |
#Ergänzt die Schlüsselattribute: |
|
41 |
for schluessel in bpy.data.textures.keys(): |
|
42 |
if(bpy.data.textures[schluessel].type == 'IMAGE'): |
|
43 |
if (schluessel[-2] == '_'): |
|
44 |
print(schluessel) |
|
45 |
bpy.data.textures[schluessel].marker_id = int(schluessel[-1]) |
|
46 |
elif (schluessel[-3] == '_'): |
|
47 |
print(schluessel) |
|
48 |
bpy.data.textures[schluessel].marker_id = int(schluessel[-2:]) |
|
49 |
elif (schluessel[-4] == '_'): |
|
50 |
print(schluessel) |
|
51 |
bpy.data.textures[schluessel].marker_id = int(schluessel[-3:]) |
|
52 |
# |
|
53 |
if(schluessel[0:5] == "ALVAR"): |
|
54 |
print("Lib: ALVAR") |
|
55 |
bpy.data.textures[schluessel].library = "ALVAR" |
|
56 |
elif(schluessel[0:4] == "BART"): |
|
57 |
print("Lib: BART") |
|
58 |
bpy.data.textures[schluessel].library = "BART" |
|
59 |
return{'FINISHED'} |
plugin_blender/view.py | ||
---|---|---|
1 |
import bpy |
|
2 |
|
|
3 |
class GraphischeOberflaeche(bpy.types.Panel): |
|
4 |
"""Zeigt die graphische Oberfläche an""" |
|
5 |
bl_idname = "RENDER_PT_select" |
|
6 |
bl_label = "Teste für Markertracking" |
|
7 |
bl_space_type = 'PROPERTIES' |
|
8 |
bl_region_type = 'WINDOW' |
|
9 |
bl_context = "render" |
|
10 |
bl_options = {'DEFAULT_CLOSED'} |
|
11 |
|
|
12 |
|
|
13 |
@classmethod |
|
14 |
def poll(cls, context): |
|
15 |
return True |
|
16 |
|
|
17 |
def draw_header(self, context): |
|
18 |
pass |
|
19 |
|
|
20 |
def draw(self, context): |
|
21 |
#Eigenschaften der obersten Ebene |
|
22 |
layout = self.layout |
|
23 |
layout.prop(bpy.context.scene.markerRender,"kameraID",text="Kamera") |
|
24 |
layout.prop(bpy.context.scene.markerRender,"kameraDatenID",text="Kam.datenblock") |
|
25 |
#Kästen erzeugen |
|
26 |
kasten1 = layout.box() |
|
27 |
kasten1.label("Erzeugung") |
|
28 |
kasten2 = layout.box() |
|
29 |
kasten2.label("Anpassung") |
|
30 |
kasten3 = layout.box() |
|
31 |
kasten3.label("Positionsdaten ausgeben") |
|
32 |
kasten4 = layout.box() |
|
33 |
kasten4.label("Texturen") |
|
34 |
# 1. Kasten füllen (Erzeugung) |
|
35 |
zeile1 = kasten1.row() |
|
36 |
zeile1.prop(bpy.context.scene.markerRender,"newMarkerID",text="nächste Nummer") |
|
37 |
zeile1.prop(bpy.context.scene.markerRender,"incrementNewMarkerID",text="autom. Erhöhen") |
|
38 |
zeile2 = kasten1.row() |
|
39 |
zeile2.prop(bpy.context.scene.markerRender,"kontrastErhoehen",text="hoher Kontrast") |
|
40 |
kasten1.operator("mesh.primitive_marker_add") |
|
41 |
# 2. Kasten füllen (Anpassung) |
|
42 |
kasten2.operator("scene.adjust_units",icon="SCENE_DATA") |
|
43 |
kasten2.operator("camera.adjust_camera",icon="CAMERA_DATA") |
|
44 |
kasten2.operator("render.adjust_dimensions",icon="RENDER_REGION") |
|
45 |
# 3. Kasten füllen (Positionsdaten ausgeben) |
|
46 |
k3_zeile1 = kasten3.row() |
|
47 |
k3_zeile1.prop(bpy.context.scene.markerRender,"markerID",text="Marker") |
|
48 |
k3_zeile2 = kasten3.row() |
|
49 |
k3_zeile2.prop(bpy.context.scene.markerRender,"dateipfad",text="") |
|
50 |
kasten3.operator("print_object.position",text="Ausgeben",icon="FILE_TEXT") |
|
51 |
# 4. Kasten füllen (Texturen) |
|
52 |
k4_zeile1 = kasten4.row() |
|
53 |
k4_zeile1.operator("texture.to_bart",icon="TEXTURE") |
|
54 |
k4_zeile1.operator("texture.to_alvar",icon="TEXTURE") |
Also available in: Unified diff