Browse Source

Implement Circle Cameras

This includes circle cameras of the manual and auto-region variety
pull/105/head
Adam Johnson 7 years ago
parent
commit
de23d77649
Signed by: Hoikas
GPG Key ID: 0B6515D6FF6F271E
  1. 54
      korman/exporter/camera.py
  2. 8
      korman/properties/modifiers/region.py
  3. 42
      korman/properties/prop_camera.py
  4. 16
      korman/ui/ui_camera.py

54
korman/exporter/camera.py

@ -28,8 +28,6 @@ class CameraConverter:
trans_props = camera_props.transition trans_props = camera_props.transition
brain.poaOffset = hsVector3(*camera_props.poa_offset) brain.poaOffset = hsVector3(*camera_props.poa_offset)
if isinstance(brain, plCameraBrain1_Avatar):
brain.offset = hsVector3(*camera_props.pos_offset)
if camera_props.poa_type == "object": if camera_props.poa_type == "object":
brain.subject = self._mgr.find_create_key(plSceneObject, bl=camera_props.poa_object) brain.subject = self._mgr.find_create_key(plSceneObject, bl=camera_props.poa_object)
@ -84,6 +82,55 @@ class CameraConverter:
# TODO: do we need to do something about animations here? # TODO: do we need to do something about animations here?
return mod return mod
def _export_circle_camera(self, so, bo, props):
brain = self._mgr.find_create_object(plCameraBrain1_Circle, so=so)
self._convert_brain(so, bo, props, brain)
# Circle Camera specific stuff ahoy!
if props.poa_type == "avatar":
brain.circleFlags |= plCameraBrain1_Circle.kCircleLocalAvatar
elif props.poa_type == "object":
brain.poaObject = self._mgr.find_create_key(plSceneObject, bl=props.poa_object)
else:
self._report.warn("Circle Camera '{}' has no Point of Attention. Is this intended?", bo.name, indent=3)
if props.circle_pos == "farthest":
brain.circleFlags |= plCameraBrain1_Circle.kFarthest
# If no center object is specified, we will use the camera object's location.
# We will use a simple vector for this object to make life simpler, however,
# specifying an actual center allows you to do interesting things like animate the center...
# Fascinating! Therefore, we will expose the Plasma Object...
if props.circle_center is None:
brain.center = hsVector3(*bo.location)
else:
brain.centerObject = self._mgr.find_create_key(plSceneObject, bl=props.circle_center)
# This flag has no effect in CWE, but I'm using it for correctness' sake
brain.circleFlags |= plCameraBrain1_Circle.kHasCenterObject
# PlasmaMAX forces these values so the circle camera is rather slow, which is somewhat
# sensible to me. Fast circular motion seems like a poor idea to me... If we want these
# values to be customizable, we probably want add some kind of range limitation or at least
# a flashing red light in the UI...
brain.acceleration = 10.0
brain.deceleration = 10.0
brain.velocity = 15.0
# Related to above, circle cameras use a slightly different velocity method.
# This is stored in Plasma as a fraction of the circle's circumference. It makes
# more sense to me to present it in terms of degrees per second, however.
# NOTE that Blender returns radians!!!
brain.cirPerSec = props.circle_velocity / (2 * math.pi)
# I consider this clever... If we have a center object, we use the magnitude of the displacement
# of the camera's object to the center object (at frame 0) to determine the radius. If no center
# object is specified, we allow the user to specify the radius.
# Well, it's clever until you realize it's the same thing Cyan did in PlasmaMAX... But it's harder
# here because Blendsucks.
brain.radius = props.get_circle_radius(bo)
# Done already?
return brain
def _export_fixed_camera(self, so, bo, props): def _export_fixed_camera(self, so, bo, props):
brain = self._mgr.find_create_object(plCameraBrain1_Fixed, so=so) brain = self._mgr.find_create_object(plCameraBrain1_Fixed, so=so)
self._convert_brain(so, bo, props, brain) self._convert_brain(so, bo, props, brain)
@ -93,6 +140,9 @@ class CameraConverter:
def _export_follow_camera(self, so, bo, props): def _export_follow_camera(self, so, bo, props):
brain = self._mgr.find_create_object(plCameraBrain1_Avatar, so=so) brain = self._mgr.find_create_object(plCameraBrain1_Avatar, so=so)
self._convert_brain(so, bo, props, brain) self._convert_brain(so, bo, props, brain)
# Follow camera specific stuff ahoy!
brain.offset = hsVector3(*camera_props.pos_offset)
return brain return brain
@property @property

8
korman/properties/modifiers/region.py

@ -69,7 +69,8 @@ class PlasmaCameraRegion(PlasmaModifierProperties):
camera_type = EnumProperty(name="Camera Type", camera_type = EnumProperty(name="Camera Type",
description="What kind of camera should be used?", description="What kind of camera should be used?",
items=[("auto", "Auto Follow Camera", "Automatically generated camera"), items=[("auto_follow", "Auto Follow Camera", "Automatically generated follow camera"),
("auto_circle", "Auto Circle Camera", "Automatically generated circle camera"),
("manual", "Manual Camera", "User specified camera object")], ("manual", "Manual Camera", "User specified camera object")],
options=set()) options=set())
camera_object = PointerProperty(name="Camera", camera_object = PointerProperty(name="Camera",
@ -86,9 +87,12 @@ class PlasmaCameraRegion(PlasmaModifierProperties):
camera_so_key = exporter.mgr.find_create_key(plSceneObject, bl=self.camera_object) camera_so_key = exporter.mgr.find_create_key(plSceneObject, bl=self.camera_object)
camera_props = self.camera_object.data.plasma_camera.settings camera_props = self.camera_object.data.plasma_camera.settings
else: else:
assert self.camera_type[:4] == "auto"
# Wheedoggy! We get to export the doggone camera now. # Wheedoggy! We get to export the doggone camera now.
camera_props = self.auto_camera camera_props = self.auto_camera
exporter.camera.export_camera(so, bo, "follow", camera_props) camera_type = self.camera_type[5:]
exporter.camera.export_camera(so, bo, camera_type, camera_props)
# Setup physical stuff # Setup physical stuff
phys_mod = bo.plasma_modifiers.collision phys_mod = bo.plasma_modifiers.collision

42
korman/properties/prop_camera.py

@ -17,8 +17,9 @@ import bpy
from bpy.props import * from bpy.props import *
import math import math
camera_types = [("follow", "Follow Camera", "Camera follows an object."), camera_types = [("circle", "Circle Camera", "The camera circles a fixed point"),
("fixed", "Fixed Camera", "Camera is fixed in one location.")] ("follow", "Follow Camera", "The camera follows an object"),
("fixed", "Fixed Camera", "The camera is fixed in one location")]
class PlasmaTransition(bpy.types.PropertyGroup): class PlasmaTransition(bpy.types.PropertyGroup):
poa_acceleration = FloatProperty(name="PoA Acceleration", poa_acceleration = FloatProperty(name="PoA Acceleration",
@ -142,6 +143,43 @@ class PlasmaCameraProperties(bpy.types.PropertyGroup):
description="The camera should be considered the Age's primary camera.", description="The camera should be considered the Age's primary camera.",
options=set()) options=set())
# Cricle Camera
def _get_circle_radius(self):
# This is coming from the UI, so we need to get the active object from
# Blender's context and pass that on to the actual getter.
return self.get_circle_radius(bpy.context.object)
def _set_circle_radius(self, value):
# Don't really care about error checking...
self.circle_radius_value = value
circle_center = PointerProperty(name="Center",
description="Center of the circle camera's orbit",
type=bpy.types.Object,
options=set())
circle_pos = EnumProperty(name="Position on Circle",
description="The point on the circle the camera moves to",
items=[("closest", "Closest Point", "The camera moves to point on the circle closest to the Point of Attention"),
("farthest", "Farthest Point", "The point farthest from the Point of Attention")],
options=set())
circle_velocity = FloatProperty(name="Velocity",
description="Velocity of the circle camera in degrees per second",
min=0.0, max=math.radians(360.0), precision=0, default=math.radians(36.0),
subtype="ANGLE", options=set())
circle_radius_ui = FloatProperty(name="Radius",
description="Radius at which the circle camera should orbit the Point of Attention",
min=0.0, get=_get_circle_radius, set=_set_circle_radius, options=set())
circle_radius_value = FloatProperty(name="INTERNAL: Radius",
description="Radius at which the circle camera should orbit the Point of Attention",
min=0.0, default=8.5, options={"HIDDEN"})
def get_circle_radius(self, bo):
"""Gets the circle camera radius for this camera when it is attached to the given Object"""
assert bo is not None
if self.circle_center is not None:
vec = bo.location - self.circle_center.location
return vec.magnitude
return self.circle_radius_value
def harvest_actors(self): def harvest_actors(self):
if self.poa_type == "object": if self.poa_type == "object":
return set((self.poa_object.name),) return set((self.poa_object.name),)

16
korman/ui/ui_camera.py

@ -59,7 +59,7 @@ def draw_camera_properties(cam_type, props, layout, context):
col = split.column() col = split.column()
col.label("Camera Mode:") col.label("Camera Mode:")
col = col.column() col = col.column()
col.alert = cam_type == "follow" and props.poa_type == "none" col.alert = cam_type != "fixed" and props.poa_type == "none"
col.prop(props, "poa_type", text="") col.prop(props, "poa_type", text="")
col.alert = False col.alert = False
row = col.row() row = col.row()
@ -98,6 +98,7 @@ def draw_camera_properties(cam_type, props, layout, context):
col = split.column() col = split.column()
# Position Transitions # Position Transitions
col.active = cam_type != "circle"
col.label("Default Position Transition:") col.label("Default Position Transition:")
col.prop(trans, "pos_acceleration", text="Acceleration") col.prop(trans, "pos_acceleration", text="Acceleration")
col.prop(trans, "pos_deceleration", text="Deceleration") col.prop(trans, "pos_deceleration", text="Deceleration")
@ -126,3 +127,16 @@ def draw_camera_properties(cam_type, props, layout, context):
_draw_gated_prop(col, props, "limit_zoom", "zoom_min") _draw_gated_prop(col, props, "limit_zoom", "zoom_min")
_draw_gated_prop(col, props, "limit_zoom", "zoom_max") _draw_gated_prop(col, props, "limit_zoom", "zoom_max")
_draw_gated_prop(col, props, "limit_zoom", "zoom_rate") _draw_gated_prop(col, props, "limit_zoom", "zoom_rate")
# Circle Camera Stuff
layout.separator()
split = layout.split()
col = split.column()
col.active = cam_type == "circle"
col.label("Circle Camera:")
col.prop(props, "circle_center", text="")
col.prop(props, "circle_pos", text="")
col.prop(props, "circle_velocity")
row = col.row(align=True)
row.active = props.circle_center is None
row.prop(props, "circle_radius_ui")

Loading…
Cancel
Save