|
@@ -19,9 +19,12 @@ else:
|
|
|
import json
|
|
|
from pathlib import Path
|
|
|
from dataclasses import dataclass
|
|
|
- from mathutils import Euler
|
|
|
+ from mathutils import Euler, Vector, Quaternion, Matrix
|
|
|
import math
|
|
|
import os
|
|
|
+ import base64
|
|
|
+ import numpy as np
|
|
|
+ from pyquaternion import Quaternion
|
|
|
|
|
|
# from . import zs_renderscene as zsrs # noqa
|
|
|
|
|
@@ -37,6 +40,38 @@ bl_info = {
|
|
|
}
|
|
|
|
|
|
|
|
|
+# -------------------------------------------------------------------
|
|
|
+# Convert Data Functions
|
|
|
+# -------------------------------------------------------------------
|
|
|
+def convert_loc(x):
|
|
|
+ return u * Vector([x[0], -x[2], x[1]])
|
|
|
+
|
|
|
+
|
|
|
+def convert_quat(q):
|
|
|
+ return Quaternion([q[3], q[0], -q[2], q[1]])
|
|
|
+
|
|
|
+
|
|
|
+def convert_scale(s):
|
|
|
+ return Vector([s[0], s[2], s[1]])
|
|
|
+
|
|
|
+
|
|
|
+def local_rotation(obj, rotation_before, rot):
|
|
|
+ """Appends a local rotation to vnode's world transform:
|
|
|
+ (new world transform) = (old world transform) @ (rot)
|
|
|
+ without changing the world transform of vnode's children.
|
|
|
+
|
|
|
+ For correctness, rot must be a signed permutation of the axes
|
|
|
+ (eg. (X Y Z)->(X -Z Y)) OR vnode's scale must always be uniform.
|
|
|
+ """
|
|
|
+ rotation_before = Quaternion((1, 0, 0, 0))
|
|
|
+ obj.rotation_before @= rot
|
|
|
+
|
|
|
+ # # Append the inverse rotation after children's TRS to cancel it out.
|
|
|
+ # rot_inv = rot.conjugated()
|
|
|
+ # for child in gltf.vnodes[vnode_id].children:
|
|
|
+ # gltf.vnodes[child].rotation_after = rot_inv @ gltf.vnodes[child].rotation_after
|
|
|
+
|
|
|
+
|
|
|
# -------------------------------------------------------------------
|
|
|
# Functions
|
|
|
# -------------------------------------------------------------------
|
|
@@ -62,10 +97,21 @@ basic_shapes_asset = AssetData(
|
|
|
)
|
|
|
|
|
|
|
|
|
+def convert_base64_string_to_object(base64_string):
|
|
|
+ bytes = base64.b64decode(base64_string)
|
|
|
+ string = bytes.decode("ascii")
|
|
|
+
|
|
|
+ return json.loads(string)
|
|
|
+ return string
|
|
|
+
|
|
|
+
|
|
|
def load_scene():
|
|
|
+
|
|
|
print("Loading Scene")
|
|
|
# load scene data
|
|
|
+
|
|
|
scene_data = load_scene_data()
|
|
|
+ print(scene_data)
|
|
|
# create parent collections
|
|
|
create_parent_collections(product_asset.collection_name)
|
|
|
create_parent_collections(element_asset.collection_name)
|
|
@@ -101,18 +147,41 @@ def load_scene():
|
|
|
set_cryptomatte_objects("01_Products", "mask_product")
|
|
|
|
|
|
|
|
|
+def invert_id_name(json_data):
|
|
|
+ for obj in json_data["scene"]["objects"]:
|
|
|
+ obj["name"], obj["id"] = obj["id"], obj["name"]
|
|
|
+ return json_data
|
|
|
+
|
|
|
+
|
|
|
def load_scene_data():
|
|
|
- print("Loading Scene Data")
|
|
|
+ # print("Loading Scene Data")
|
|
|
+ # # load scene data
|
|
|
+
|
|
|
+ # # to be replaced with actual data
|
|
|
+ # # open scene_info.json
|
|
|
+ # script_path = Path(__file__).resolve()
|
|
|
+ # scene_data_path = script_path.parent / "sample_scene" / "scene_info.json"
|
|
|
+ # with scene_data_path.open() as file:
|
|
|
+ # scene_data = json.load(file)
|
|
|
+ # print(scene_data)
|
|
|
+ # return scene_data
|
|
|
+
|
|
|
# load scene data
|
|
|
+ print("Loading Scene Data")
|
|
|
+ if bpy.context.scene.load_local_DB:
|
|
|
+ loaded_scene_data = bpy.context.scene.config_string
|
|
|
+ # check if loaded_scene_data is base64 encoded
|
|
|
+ if loaded_scene_data.startswith("ey"):
|
|
|
+ scene_data = convert_base64_string_to_object(loaded_scene_data)
|
|
|
+ else:
|
|
|
+ scene_data = json.loads(loaded_scene_data)
|
|
|
|
|
|
- # to be replaced with actual data
|
|
|
- # open scene_info.json
|
|
|
- script_path = Path(__file__).resolve()
|
|
|
- scene_data_path = script_path.parent / "sample_scene" / "scene_info.json"
|
|
|
- with scene_data_path.open() as file:
|
|
|
- scene_data = json.load(file)
|
|
|
- print(scene_data)
|
|
|
- return scene_data
|
|
|
+ else:
|
|
|
+ scene_data = json.loads(bpy.context.scene.shot_info_ai)
|
|
|
+
|
|
|
+ invert_scene_data = invert_id_name(scene_data)
|
|
|
+
|
|
|
+ return invert_scene_data
|
|
|
|
|
|
|
|
|
def load_objects_data(scene_data, object_type: str):
|
|
@@ -123,6 +192,8 @@ def load_objects_data(scene_data, object_type: str):
|
|
|
if object["group_type"] == object_type:
|
|
|
# get additional object data by id and combine with object data
|
|
|
object_data = get_object_data_by_id(object["id"])
|
|
|
+ # temporary fix
|
|
|
+ # object_data = get_object_data_by_id(object["name"])
|
|
|
object.update(object_data)
|
|
|
objects_data.append(object)
|
|
|
return objects_data
|
|
@@ -231,11 +302,23 @@ def append_active_layers(newCollectionName, product_info, asset_data: AssetData)
|
|
|
|
|
|
# need to redo this in the future
|
|
|
if "Animation_Target" in collection.name:
|
|
|
- # print object name from collection
|
|
|
|
|
|
- collection.objects[0].location = product_info["properties"][
|
|
|
+ # set the x location
|
|
|
+ collection.objects[0].location.x = product_info["properties"][
|
|
|
+ "transform"
|
|
|
+ ]["position"][0]
|
|
|
+ # set the y location
|
|
|
+ collection.objects[0].location.y = -product_info["properties"][
|
|
|
"transform"
|
|
|
- ]["position"]
|
|
|
+ ]["position"][2]
|
|
|
+ # set the z location
|
|
|
+ collection.objects[0].location.z = product_info["properties"][
|
|
|
+ "transform"
|
|
|
+ ]["position"][1]
|
|
|
+
|
|
|
+ # collection.objects[0].location = product_info["properties"][
|
|
|
+ # "transform"
|
|
|
+ # ]["position"]
|
|
|
|
|
|
# collection.objects[0].rotation_euler = product_info["properties"][
|
|
|
# "transform"
|
|
@@ -244,9 +327,15 @@ def append_active_layers(newCollectionName, product_info, asset_data: AssetData)
|
|
|
rotation_in_degrees = product_info["properties"]["transform"][
|
|
|
"rotation"
|
|
|
]
|
|
|
- rotation_in_radians = [math.radians(deg) for deg in rotation_in_degrees]
|
|
|
|
|
|
- collection.objects[0].rotation_euler = rotation_in_radians
|
|
|
+ rotation_in_degrees[0] = rotation_in_degrees[0] + 90
|
|
|
+
|
|
|
+ # set object rotation in euler from radians
|
|
|
+ collection.objects[0].rotation_euler = (
|
|
|
+ math.radians(rotation_in_degrees[0]),
|
|
|
+ math.radians(rotation_in_degrees[2]),
|
|
|
+ math.radians(rotation_in_degrees[1]),
|
|
|
+ )
|
|
|
|
|
|
collection.objects[0].scale = product_info["properties"]["transform"][
|
|
|
"scale"
|
|
@@ -334,50 +423,74 @@ def create_cameras(scene_data):
|
|
|
else:
|
|
|
return
|
|
|
|
|
|
- for camera_data in scene_data["scene"]["cameras"]:
|
|
|
- # Create a new camera object
|
|
|
- bpy.ops.object.camera_add()
|
|
|
-
|
|
|
- # Get the newly created camera
|
|
|
- camera = bpy.context.object
|
|
|
-
|
|
|
- # Set the camera's name
|
|
|
- camera.name = camera_data["name"]
|
|
|
-
|
|
|
- # Set the camera's position
|
|
|
- position = camera_data["properties"]["transform"]["position"]
|
|
|
- camera.location.x = position[0]
|
|
|
- camera.location.y = position[1]
|
|
|
- camera.location.z = position[2]
|
|
|
-
|
|
|
- # Set the camera's rotation
|
|
|
- rotation = camera_data["properties"]["transform"]["rotation"]
|
|
|
- # Convert the rotation from degrees to radians
|
|
|
- rotation = [math.radians(r) for r in rotation]
|
|
|
- camera.rotation_euler = Euler(rotation, "XYZ")
|
|
|
-
|
|
|
- # Set the camera's lens properties
|
|
|
- lens = camera_data["properties"]["lens"]
|
|
|
- type_mapping = {
|
|
|
- "PERSPECTIVE": "PERSP",
|
|
|
- "ORTHOGRAPHIC": "ORTHO",
|
|
|
- "PANORAMIC": "PANO",
|
|
|
- }
|
|
|
- camera.data.type = type_mapping.get(lens["type"].upper(), "PERSP")
|
|
|
- camera.data.angle = math.radians(lens["fov"])
|
|
|
- camera.data.clip_start = lens["near"]
|
|
|
- camera.data.clip_end = lens["far"]
|
|
|
-
|
|
|
- # Add the camera to the 05_Cameras collection
|
|
|
- collection.objects.link(camera)
|
|
|
- bpy.context.scene.collection.objects.unlink(camera)
|
|
|
-
|
|
|
- # Set the camera as the active camera if "active" is true
|
|
|
- if camera_data["properties"]["active"]:
|
|
|
- bpy.context.scene.camera = camera
|
|
|
+
|
|
|
+# Assuming `scene_data` and `collection` are already defined
|
|
|
+for camera_data in scene_data["scene"]["cameras"]:
|
|
|
+ # Create a new camera object
|
|
|
+ bpy.ops.object.camera_add()
|
|
|
+
|
|
|
+ # Get the newly created camera
|
|
|
+ camera = bpy.context.object
|
|
|
+
|
|
|
+ # Set the camera's name
|
|
|
+ camera.name = camera_data["name"]
|
|
|
+
|
|
|
+ # Set the camera's position
|
|
|
+ position = camera_data["properties"]["transform"]["position"]
|
|
|
+ camera.location.x = position[0]
|
|
|
+ camera.location.y = -position[2]
|
|
|
+ camera.location.z = position[1]
|
|
|
+
|
|
|
+ # Set the camera's rotation
|
|
|
+ rotation = camera_data["properties"]["transform"]["rotation"]
|
|
|
+ local_rotation = Euler(
|
|
|
+ (
|
|
|
+ math.radians(rotation[0]),
|
|
|
+ math.radians(rotation[1]),
|
|
|
+ math.radians(rotation[2]),
|
|
|
+ ),
|
|
|
+ "XYZ",
|
|
|
+ )
|
|
|
+
|
|
|
+ # Apply the local rotation to the camera
|
|
|
+ camera.rotation_euler = local_rotation
|
|
|
+
|
|
|
+ # Update the camera's matrix_world to apply the local transformation
|
|
|
+ camera.matrix_world = camera.matrix_basis
|
|
|
+
|
|
|
+ # Calculate the global rotation
|
|
|
+ global_rotation = camera.matrix_world.to_euler()
|
|
|
+
|
|
|
+ # Set the camera's rotation to the global rotation
|
|
|
+ camera.rotation_euler = global_rotation
|
|
|
+
|
|
|
+ # Set the camera's lens properties
|
|
|
+ lens = camera_data["properties"]["lens"]
|
|
|
+ type_mapping = {
|
|
|
+ "PERSPECTIVE": "PERSP",
|
|
|
+ "ORTHOGRAPHIC": "ORTHO",
|
|
|
+ "PANORAMIC": "PANO",
|
|
|
+ }
|
|
|
+ camera.data.type = type_mapping.get(lens["type"].upper(), "PERSP")
|
|
|
+ camera.data.angle = math.radians(lens["fov"])
|
|
|
+ camera.data.clip_start = lens["near"]
|
|
|
+ camera.data.clip_end = lens["far"]
|
|
|
+
|
|
|
+ # Add the camera to the 05_Cameras collection
|
|
|
+ collection.objects.link(camera)
|
|
|
+ bpy.context.scene.collection.objects.unlink(camera)
|
|
|
+
|
|
|
+ # Set the camera as the active camera if "active" is true
|
|
|
+ if camera_data["properties"]["active"]:
|
|
|
+ bpy.context.scene.camera = camera
|
|
|
|
|
|
|
|
|
def set_output_paths(base_path, project_name):
|
|
|
+
|
|
|
+ # check if folder exist, if not create it
|
|
|
+ folder_path = base_path + "//" + project_name
|
|
|
+ if not os.path.exists(folder_path):
|
|
|
+ os.makedirs(folder_path)
|
|
|
# Get the current scene
|
|
|
scene = bpy.context.scene
|
|
|
|
|
@@ -388,7 +501,7 @@ def set_output_paths(base_path, project_name):
|
|
|
# Check if the node is an output node
|
|
|
if node.type == "OUTPUT_FILE":
|
|
|
# Set the base path of the output node
|
|
|
- node.base_path = base_path + "//" + project_name
|
|
|
+ node.base_path = folder_path
|
|
|
# Iterate over all file slots of the output node
|
|
|
# for file_slot in node.file_slots:
|
|
|
# # Set the path of the file slot
|
|
@@ -811,9 +924,16 @@ class ZSSD_PT_Main(ZSSDPanel, bpy.types.Panel):
|
|
|
|
|
|
col.label(text="Stable Diffusion Connection")
|
|
|
|
|
|
+ col.prop(context.scene, "load_local_DB")
|
|
|
+
|
|
|
+ col.prop(context.scene, "config_string")
|
|
|
+
|
|
|
# load scene button
|
|
|
+
|
|
|
col.operator("zs_sd_loader.load_scene", text="Load Scene")
|
|
|
|
|
|
+ col.separator()
|
|
|
+
|
|
|
# export assets button
|
|
|
col.operator("zs_canvas.export_assets", text="Export Assets")
|
|
|
|
|
@@ -832,6 +952,18 @@ def register():
|
|
|
for blender_class in blender_classes:
|
|
|
bpy.utils.register_class(blender_class)
|
|
|
|
|
|
+ bpy.types.Scene.shot_info_ai = bpy.props.StringProperty(
|
|
|
+ name="Shot Info",
|
|
|
+ )
|
|
|
+
|
|
|
+ bpy.types.Scene.config_string = bpy.props.StringProperty( # type: ignore
|
|
|
+ name="Configuration String",
|
|
|
+ )
|
|
|
+
|
|
|
+ bpy.types.Scene.load_local_DB = bpy.props.BoolProperty( # type: ignore
|
|
|
+ name="Load Local DB",
|
|
|
+ )
|
|
|
+
|
|
|
# Has to be afqter class registering to correctly register property
|
|
|
|
|
|
# register global properties
|
|
@@ -852,6 +984,9 @@ def unregister():
|
|
|
for blender_class in blender_classes:
|
|
|
bpy.utils.unregister_class(blender_class)
|
|
|
# unregister global properties
|
|
|
+ del bpy.types.Scene.shot_info_ai
|
|
|
+ del bpy.types.Scene.config_string
|
|
|
+ del bpy.types.Scene.load_local_DB
|
|
|
|
|
|
# unregister list items
|
|
|
# del bpy.types.Scene.my_list
|