feat: add virtools camera support
This commit is contained in:
292
bbp_ng/PROP_virtools_camera.py
Normal file
292
bbp_ng/PROP_virtools_camera.py
Normal file
@@ -0,0 +1,292 @@
|
||||
import bpy
|
||||
import typing, math
|
||||
from . import UTIL_functions, UTIL_virtools_types
|
||||
|
||||
# Raw Data
|
||||
|
||||
class RawVirtoolsCamera():
|
||||
# Class Member
|
||||
|
||||
mProjectionType: UTIL_virtools_types.CK_CAMERA_PROJECTION
|
||||
|
||||
mOrthographicZoom: float
|
||||
|
||||
mFrontPlane: float
|
||||
mBackPlane: float
|
||||
mFov: float
|
||||
|
||||
mAspectRatio: tuple[int, int]
|
||||
|
||||
# Class member default value
|
||||
|
||||
cDefaultProjectionType: typing.ClassVar[UTIL_virtools_types.CK_CAMERA_PROJECTION] = UTIL_virtools_types.CK_CAMERA_PROJECTION.CK_PERSPECTIVEPROJECTION
|
||||
|
||||
cDefaultOrthographicZoom: typing.ClassVar[float] = 1.0
|
||||
|
||||
cDefaultFrontPlane: typing.ClassVar[float] = 1.0
|
||||
cDefaultBackPlane: typing.ClassVar[float] = 4000.0
|
||||
cDefaultFov: typing.ClassVar[float] = 0.5
|
||||
|
||||
cDefaultAspectRatio: typing.ClassVar[tuple[int, int]] = (4, 3)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
# assign default value for each component
|
||||
self.mProjectionType = kwargs.get("mProjectionType", RawVirtoolsCamera.cDefaultProjectionType)
|
||||
|
||||
self.mOrthographicZoom = kwargs.get("mOrthographicZoom", RawVirtoolsCamera.cDefaultOrthographicZoom)
|
||||
|
||||
self.mFrontPlane = kwargs.get("mFrontPlane", RawVirtoolsCamera.cDefaultFrontPlane)
|
||||
self.mBackPlane = kwargs.get("mBackPlane", RawVirtoolsCamera.cDefaultBackPlane)
|
||||
self.mFov = kwargs.get("mFov", RawVirtoolsCamera.cDefaultFov)
|
||||
|
||||
self.mAspectRatio = kwargs.get("mAspectRatio", RawVirtoolsCamera.cDefaultAspectRatio)
|
||||
|
||||
def regulate(self) -> None:
|
||||
# everything should be positive
|
||||
self.mOrthographicZoom = max(0.0, self.mOrthographicZoom)
|
||||
self.mFrontPlane = max(0.0, self.mFrontPlane)
|
||||
self.mBackPlane = max(0.0, self.mBackPlane)
|
||||
self.mFov = max(0.0, self.mFov)
|
||||
|
||||
# aspect ratio should be positive and at least 1
|
||||
(w, h) = self.mAspectRatio
|
||||
w = max(1, w)
|
||||
h = max(1, h)
|
||||
self.mAspectRatio = (w, h)
|
||||
|
||||
# Blender Property Group
|
||||
|
||||
_g_Helper_CK_CAMERA_PROJECTION = UTIL_virtools_types.EnumPropHelper(UTIL_virtools_types.CK_CAMERA_PROJECTION)
|
||||
|
||||
class BBP_PG_virtools_camera(bpy.types.PropertyGroup):
|
||||
projection_type: bpy.props.EnumProperty(
|
||||
name = "Type",
|
||||
description = "The type of this camera.",
|
||||
items = _g_Helper_CK_CAMERA_PROJECTION.generate_items(),
|
||||
default = _g_Helper_CK_CAMERA_PROJECTION.to_selection(RawVirtoolsCamera.cDefaultProjectionType),
|
||||
translation_context = 'BBP_PG_virtools_camera/property'
|
||||
) # type: ignore
|
||||
|
||||
orthographic_zoom: bpy.props.FloatProperty(
|
||||
name = "Orthographic Zoom",
|
||||
description = "Defines the orthographic zoom.",
|
||||
min = 0.0,
|
||||
soft_min = 0.0,
|
||||
soft_max = 0.5,
|
||||
step = 5,
|
||||
default = RawVirtoolsCamera.cDefaultOrthographicZoom,
|
||||
translation_context = 'BBP_PG_virtools_camera/property'
|
||||
) # type: ignore
|
||||
|
||||
front_plane: bpy.props.FloatProperty(
|
||||
name = "Front Plane",
|
||||
description = "Defines the front plane.",
|
||||
min = 0.0,
|
||||
soft_min = 0.0,
|
||||
soft_max = 5000.0,
|
||||
step = 100,
|
||||
default = RawVirtoolsCamera.cDefaultFrontPlane,
|
||||
translation_context = 'BBP_PG_virtools_camera/property'
|
||||
) # type: ignore
|
||||
|
||||
back_plane: bpy.props.FloatProperty(
|
||||
name = "Back Plane",
|
||||
description = "Defines the back plane.",
|
||||
min = 0.0,
|
||||
soft_min = 0.0,
|
||||
soft_max = 5000.0,
|
||||
step = 100,
|
||||
default = RawVirtoolsCamera.cDefaultBackPlane,
|
||||
translation_context = 'BBP_PG_virtools_camera/property'
|
||||
) # type: ignore
|
||||
|
||||
fov: bpy.props.FloatProperty(
|
||||
name = "Field of View",
|
||||
description = "Defines the field of view.",
|
||||
subtype = 'ANGLE',
|
||||
min = 0.0,
|
||||
max = math.radians(180.0),
|
||||
step = 100,
|
||||
precision = 100,
|
||||
default = RawVirtoolsCamera.cDefaultFov,
|
||||
translation_context = 'BBP_PG_virtools_camera/property'
|
||||
) # type: ignore
|
||||
|
||||
aspect_ratio_w: bpy.props.IntProperty(
|
||||
name = "Aspect Ratio Width",
|
||||
description = "Defines the width of aspect ratio.",
|
||||
min = 1,
|
||||
soft_min = 1,
|
||||
soft_max = 40,
|
||||
step = 1,
|
||||
default = RawVirtoolsCamera.cDefaultAspectRatio[0],
|
||||
translation_context = 'BBP_PG_virtools_camera/property'
|
||||
) # type: ignore
|
||||
|
||||
aspect_ratio_h: bpy.props.IntProperty(
|
||||
name = "Aspect Ratio Height",
|
||||
description = "Defines the height of aspect ratio.",
|
||||
min = 1,
|
||||
soft_min = 1,
|
||||
soft_max = 40,
|
||||
step = 1,
|
||||
default = RawVirtoolsCamera.cDefaultAspectRatio[1],
|
||||
translation_context = 'BBP_PG_virtools_camera/property'
|
||||
) # type: ignore
|
||||
|
||||
# Getter Setter and Applyer
|
||||
|
||||
def get_virtools_camera(cam: bpy.types.Camera) -> BBP_PG_virtools_camera:
|
||||
return cam.virtools_camera
|
||||
|
||||
def get_raw_virtools_camera(cam: bpy.types.Camera) -> RawVirtoolsCamera:
|
||||
props: BBP_PG_virtools_camera = get_virtools_camera(cam)
|
||||
rawdata: RawVirtoolsCamera = RawVirtoolsCamera()
|
||||
|
||||
rawdata.mProjectionType = _g_Helper_CK_CAMERA_PROJECTION.get_selection(props.projection_type)
|
||||
|
||||
rawdata.mOrthographicZoom = props.orthographic_zoom
|
||||
|
||||
rawdata.mFrontPlane = props.front_plane
|
||||
rawdata.mBackPlane = props.back_plane
|
||||
rawdata.mFov = props.fov
|
||||
|
||||
rawdata.mAspectRatio = (props.aspect_ratio_w, props.aspect_ratio_h)
|
||||
|
||||
rawdata.regulate()
|
||||
return rawdata
|
||||
|
||||
def set_raw_virtools_camera(cam: bpy.types.Camera, rawdata: RawVirtoolsCamera) -> None:
|
||||
props: BBP_PG_virtools_camera = get_virtools_camera(cam)
|
||||
|
||||
props.projection_type = _g_Helper_CK_CAMERA_PROJECTION.to_selection(rawdata.mProjectionType)
|
||||
|
||||
props.orthographic_zoom = rawdata.mOrthographicZoom
|
||||
|
||||
props.front_plane = rawdata.mFrontPlane
|
||||
props.back_plane = rawdata.mBackPlane
|
||||
props.fov = rawdata.mFov
|
||||
|
||||
(props.aspect_ratio_w, props.aspect_ratio_h) = rawdata.mAspectRatio
|
||||
|
||||
def apply_to_blender_camera(cam: bpy.types.Camera) -> None:
|
||||
# get raw data first
|
||||
rawdata: RawVirtoolsCamera = get_raw_virtools_camera(cam)
|
||||
|
||||
# set camera type
|
||||
match(rawdata.mProjectionType):
|
||||
case UTIL_virtools_types.CK_CAMERA_PROJECTION.CK_PERSPECTIVEPROJECTION:
|
||||
cam.type = 'PERSP'
|
||||
case UTIL_virtools_types.CK_CAMERA_PROJECTION.CK_ORTHOGRAPHICPROJECTION:
|
||||
cam.type = 'ORTHO'
|
||||
|
||||
# set orthographic zoom
|
||||
cam.ortho_scale = rawdata.mOrthographicZoom
|
||||
|
||||
# front and back plane
|
||||
cam.clip_start = rawdata.mFrontPlane
|
||||
cam.clip_end = rawdata.mBackPlane
|
||||
|
||||
# fov
|
||||
cam.lens_unit = 'FOV'
|
||||
cam.angle = rawdata.mFov
|
||||
|
||||
# Operators
|
||||
|
||||
class BBP_OT_apply_virtools_camera(bpy.types.Operator):
|
||||
"""Apply Virtools Camera to Blender Camera."""
|
||||
bl_idname = "bbp.apply_virtools_camera"
|
||||
bl_label = "Apply to Blender Camera"
|
||||
bl_options = {'UNDO'}
|
||||
bl_translation_context = 'BBP_OT_apply_virtools_camera'
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.camera is not None
|
||||
|
||||
def execute(self, context):
|
||||
cam: bpy.types.Camera = context.camera
|
||||
apply_to_blender_camera(cam)
|
||||
return {'FINISHED'}
|
||||
|
||||
# Display Panel
|
||||
|
||||
class BBP_PT_virtools_camera(bpy.types.Panel):
|
||||
"""Show Virtools Camera Properties"""
|
||||
bl_label = "Virtools Camera"
|
||||
bl_idname = "BBP_PT_virtools_camera"
|
||||
bl_space_type = 'PROPERTIES'
|
||||
bl_region_type = 'WINDOW'
|
||||
bl_context = "data" # idk why blender use `data` as the camera tab same as mesh.
|
||||
bl_translation_context = 'BBP_PT_virtools_camera'
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.camera is not None
|
||||
|
||||
def draw(self, context):
|
||||
# get layout and target
|
||||
layout = self.layout
|
||||
cam: bpy.types.Camera = context.camera
|
||||
props: BBP_PG_virtools_camera = get_virtools_camera(cam)
|
||||
rawdata: RawVirtoolsCamera = get_raw_virtools_camera(cam)
|
||||
|
||||
# draw operator
|
||||
layout.operator(
|
||||
BBP_OT_apply_virtools_camera.bl_idname, text='Apply', icon='NODETREE',
|
||||
text_ctxt='BBP_PT_virtools_camera/draw')
|
||||
|
||||
# draw data
|
||||
layout.separator()
|
||||
# show camera type first
|
||||
layout.prop(props, 'projection_type')
|
||||
# all camera has front and back plane
|
||||
layout.label(text='Clipping', text_ctxt='BBP_PT_virtools_camera/draw')
|
||||
sublayout = layout.column()
|
||||
sublayout.use_property_split = True
|
||||
sublayout.prop(props, 'front_plane')
|
||||
sublayout.prop(props, 'back_plane')
|
||||
|
||||
# only perspective camera has fov setting
|
||||
if rawdata.mProjectionType == UTIL_virtools_types.CK_CAMERA_PROJECTION.CK_PERSPECTIVEPROJECTION:
|
||||
layout.separator()
|
||||
layout.label(text='Perspective Parameters', text_ctxt='BBP_PT_virtools_camera/draw')
|
||||
sublayout = layout.column()
|
||||
sublayout.use_property_split = True
|
||||
sublayout.prop(props, 'fov')
|
||||
|
||||
# only orthographic camera has orthographic zoom setting
|
||||
if rawdata.mProjectionType == UTIL_virtools_types.CK_CAMERA_PROJECTION.CK_ORTHOGRAPHICPROJECTION:
|
||||
layout.separator()
|
||||
layout.label(text='Orthographic Parameters', text_ctxt='BBP_PT_virtools_camera/draw')
|
||||
sublayout = layout.column()
|
||||
sublayout.use_property_split = True
|
||||
sublayout.prop(props, 'orthographic_zoom')
|
||||
|
||||
# aspect ratio
|
||||
layout.separator()
|
||||
layout.label(text='Aspect Ratio', text_ctxt='BBP_PT_virtools_camera/draw')
|
||||
sublayout = layout.row()
|
||||
sublayout.use_property_split = False
|
||||
sublayout.prop(props, 'aspect_ratio_w', text = '', expand = True)
|
||||
sublayout.prop(props, 'aspect_ratio_h', text = '', expand = True)
|
||||
|
||||
# Register
|
||||
|
||||
def register() -> None:
|
||||
bpy.utils.register_class(BBP_PG_virtools_camera)
|
||||
bpy.utils.register_class(BBP_OT_apply_virtools_camera)
|
||||
bpy.utils.register_class(BBP_PT_virtools_camera)
|
||||
|
||||
# add into camera metadata
|
||||
bpy.types.Camera.virtools_camera = bpy.props.PointerProperty(type = BBP_PG_virtools_camera)
|
||||
|
||||
def unregister() -> None:
|
||||
# remove from metadata
|
||||
del bpy.types.Camera.virtools_camera
|
||||
|
||||
bpy.utils.unregister_class(BBP_PT_virtools_camera)
|
||||
bpy.utils.unregister_class(BBP_OT_apply_virtools_camera)
|
||||
bpy.utils.unregister_class(BBP_PG_virtools_camera)
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import bpy, mathutils
|
||||
from bpy.types import Context
|
||||
import bpy
|
||||
import typing, math
|
||||
from . import UTIL_functions, UTIL_virtools_types
|
||||
|
||||
|
||||
@@ -235,8 +235,8 @@ _g_Docstring: dict[type, dict[int, EnumDocstring]] = {
|
||||
VXMESH_LITMODE.VX_LITMESH.value: EnumDocstring("Lit", "Lighting is done by renderer using normals and face material information. "),
|
||||
},
|
||||
CK_CAMERA_PROJECTION: {
|
||||
CK_CAMERA_PROJECTION.CK_PERSPECTIVEPROJECTION.value: EnumDocstring("Perspectiveprojection", ""),
|
||||
CK_CAMERA_PROJECTION.CK_ORTHOGRAPHICPROJECTION.value: EnumDocstring("Orthographicprojection", ""),
|
||||
CK_CAMERA_PROJECTION.CK_PERSPECTIVEPROJECTION.value: EnumDocstring("Perspective projection", ""),
|
||||
CK_CAMERA_PROJECTION.CK_ORTHOGRAPHICPROJECTION.value: EnumDocstring("Orthographic projection", ""),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ UTIL_icons_manager.register()
|
||||
|
||||
# then load other modules
|
||||
from . import UTIL_translation
|
||||
from . import PROP_preferences, PROP_ptrprop_resolver, PROP_virtools_material, PROP_virtools_texture, PROP_virtools_mesh, PROP_virtools_light, PROP_virtools_group
|
||||
from . import PROP_preferences, PROP_ptrprop_resolver, PROP_virtools_material, PROP_virtools_texture, PROP_virtools_mesh, PROP_virtools_light, PROP_virtools_camera, PROP_virtools_group
|
||||
from . import PROP_ballance_element, PROP_bme_material, PROP_ballance_map_info
|
||||
from . import OP_IMPORT_bmfile, OP_EXPORT_bmfile, OP_IMPORT_virtools, OP_EXPORT_virtools
|
||||
from . import OP_UV_flatten_uv, OP_UV_rail_uv
|
||||
@@ -327,6 +327,7 @@ def register() -> None:
|
||||
PROP_virtools_texture.register()
|
||||
PROP_virtools_mesh.register()
|
||||
PROP_virtools_light.register()
|
||||
PROP_virtools_camera.register()
|
||||
PROP_virtools_group.register()
|
||||
PROP_ballance_element.register()
|
||||
PROP_bme_material.register()
|
||||
@@ -397,6 +398,7 @@ def unregister() -> None:
|
||||
PROP_bme_material.unregister()
|
||||
PROP_ballance_element.unregister()
|
||||
PROP_virtools_group.unregister()
|
||||
PROP_virtools_camera.unregister()
|
||||
PROP_virtools_light.unregister()
|
||||
PROP_virtools_mesh.unregister()
|
||||
PROP_virtools_texture.unregister()
|
||||
|
||||
Reference in New Issue
Block a user