mirror of https://github.com/H-uru/korman.git
Browse Source
This implments basic follow and fixed cameras. Currently, animating cameras and/or their field of view are/is not supported.pull/105/head
Adam Johnson
7 years ago
10 changed files with 478 additions and 0 deletions
@ -0,0 +1,104 @@
|
||||
# This file is part of Korman. |
||||
# |
||||
# Korman is free software: you can redistribute it and/or modify |
||||
# it under the terms of the GNU General Public License as published by |
||||
# the Free Software Foundation, either version 3 of the License, or |
||||
# (at your option) any later version. |
||||
# |
||||
# Korman is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with Korman. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
import bpy |
||||
import math |
||||
from PyHSPlasma import * |
||||
import weakref |
||||
|
||||
from .explosions import * |
||||
|
||||
class CameraConverter: |
||||
def __init__(self, exporter): |
||||
self._exporter = weakref.ref(exporter) |
||||
|
||||
def _convert_brain(self, so, bo, camera_props, brain): |
||||
trans_props = camera_props.transition |
||||
|
||||
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": |
||||
brain.subject = self._mgr.find_create_key(plSceneObject, bl=camera_props.poa_object) |
||||
|
||||
brain.xPanLimit = camera_props.x_pan_angle / 2.0 |
||||
brain.zPanLimit = camera_props.y_pan_angle / 2.0 |
||||
brain.panSpeed = camera_props.pan_rate |
||||
if camera_props.limit_zoom: |
||||
brain.setFlags(plCameraBrain1.kZoomEnabled, True) |
||||
brain.zoomMax = camera_props.zoom_max * (4.0 / 3.0) |
||||
brain.zoomMin = camera_props.zoom_min * (4.0 / 3.0) |
||||
brain.zoomRate = camera_props.zoom_rate |
||||
|
||||
brain.acceleration = trans_props.pos_acceleration |
||||
brain.deceleration = trans_props.pos_deceleration |
||||
brain.velocity = trans_props.pos_velocity |
||||
brain.poaAcceleration = trans_props.poa_acceleration |
||||
brain.poaDeceleration = trans_props.poa_deceleration |
||||
brain.poaVelocity = trans_props.poa_velocity |
||||
|
||||
if trans_props.pos_cut: |
||||
brain.setFlags(plCameraBrain1.kCutPos, True) |
||||
if trans_props.poa_cut: |
||||
brain.setFlags(plCameraBrain1.kCutPOA, True) |
||||
if camera_props.poa_type == "avatar": |
||||
brain.setFlags(plCameraBrain1.kFollowLocalAvatar, True) |
||||
if camera_props.maintain_los: |
||||
brain.setFlags(plCameraBrain1.kMaintainLOS, True) |
||||
if camera_props.poa_worldspace: |
||||
brain.setFlags(plCameraBrain1.kWorldspacePOA, True) |
||||
if camera_props.pos_worldspace: |
||||
brain.setFlags(plCameraBrain1.kWorldspacePos, True) |
||||
if camera_props.ignore_subworld: |
||||
brain.setFlags(plCameraBrain1.kIgnoreSubworldMovement, True) |
||||
if camera_props.fall_vertical: |
||||
brain.setFlags(plCameraBrain1.kVerticalWhenFalling, True) |
||||
if camera_props.fast_run: |
||||
brain.setFlags(plCameraBrain1.kSpeedUpWhenRunning, True) |
||||
|
||||
def export_camera(self, so, bo, camera_type, camera_props): |
||||
mod = self._export_camera_modifier(so, bo, camera_props) |
||||
brain = getattr(self, "_export_{}_camera".format(camera_type))(so, bo, camera_props) |
||||
mod.brain = brain.key |
||||
|
||||
def _export_camera_modifier(self, so, bo, props): |
||||
# PlasmaMAX allows the user to specify the horizontal OR vertical FOV, but not both. |
||||
# We only allow setting horizontal FOV (how often do you look up?), however. |
||||
# Plasma assumes 4:3 aspect ratio... |
||||
mod = self._mgr.find_create_object(plCameraModifier, so=so) |
||||
fov = props.fov |
||||
mod.fovW, mod.fovH = math.degrees(fov), math.degrees(fov * (3.0 / 4.0)) |
||||
|
||||
# TODO: do we need to do something about animations here? |
||||
return mod |
||||
|
||||
def _export_fixed_camera(self, so, bo, props): |
||||
brain = self._mgr.find_create_object(plCameraBrain1_Fixed, so=so) |
||||
self._convert_brain(so, bo, props, brain) |
||||
# TODO: animations??? |
||||
return brain |
||||
|
||||
def _export_follow_camera(self, so, bo, props): |
||||
brain = self._mgr.find_create_object(plCameraBrain1_Avatar, so=so) |
||||
self._convert_brain(so, bo, props, brain) |
||||
return brain |
||||
|
||||
@property |
||||
def _mgr(self): |
||||
return self._exporter().mgr |
||||
|
||||
@property |
||||
def _report(self): |
||||
return self._exporter().report |
@ -0,0 +1,160 @@
|
||||
# This file is part of Korman. |
||||
# |
||||
# Korman is free software: you can redistribute it and/or modify |
||||
# it under the terms of the GNU General Public License as published by |
||||
# the Free Software Foundation, either version 3 of the License, or |
||||
# (at your option) any later version. |
||||
# |
||||
# Korman is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with Korman. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
import bpy |
||||
from bpy.props import * |
||||
import math |
||||
|
||||
camera_types = [("follow", "Follow Camera", "Camera follows an object."), |
||||
("fixed", "Fixed Camera", "Camera is fixed in one location.")] |
||||
|
||||
class PlasmaTransition(bpy.types.PropertyGroup): |
||||
poa_acceleration = FloatProperty(name="PoA Acceleration", |
||||
description="Rate the camera's Point of Attention tracking velocity increases in feet per second squared", |
||||
min=-100.0, max=100.0, precision=0, default=60.0, |
||||
unit="ACCELERATION", options=set()) |
||||
poa_deceleration = FloatProperty(name="PoA Deceleration", |
||||
description="Rate the camera's Point of Attention tracking velocity decreases in feet per second squared", |
||||
min=-100.0, max=100.0, precision=0, default=60.0, |
||||
unit="ACCELERATION", options=set()) |
||||
poa_velocity = FloatProperty(name="PoA Velocity", |
||||
description="Maximum velocity of the camera's Point of Attention tracking", |
||||
min=-100.0, max=100.0, precision=0, default=60.0, |
||||
unit="VELOCITY", options=set()) |
||||
poa_cut = BoolProperty(name="Cut Transition", |
||||
description="The camera immediately begins tracking the Point of Attention", |
||||
options=set()) |
||||
|
||||
pos_acceleration = FloatProperty(name="Position Acceleration", |
||||
description="Rate the camera's positional velocity increases in feet per second squared", |
||||
min=-100.0, max=100.0, precision=0, default=60.0, |
||||
unit="ACCELERATION", options=set()) |
||||
pos_deceleration = FloatProperty(name="Position Deceleration", |
||||
description="Rate the camera's positional velocity decreases in feet per second squared", |
||||
min=-100.0, max=100.0, precision=0, default=60.0, |
||||
unit="ACCELERATION", options=set()) |
||||
pos_velocity = FloatProperty(name="Position Max Velocity", |
||||
description="Maximum positional velocity of the camera", |
||||
min=-100.0, max=100.0, precision=0, default=60.0, |
||||
unit="VELOCITY", options=set()) |
||||
pos_cut = BoolProperty(name="Cut Transition", |
||||
description="The camera immediately moves to its new position", |
||||
options=set()) |
||||
|
||||
|
||||
class PlasmaCameraProperties(bpy.types.PropertyGroup): |
||||
# Point of Attention |
||||
poa_type = EnumProperty(name="Point of Attention", |
||||
description="The point of attention that this camera tracks", |
||||
items=[("avatar", "Track Local Player", "Camera tracks the player's avatar"), |
||||
("object", "Track Object", "Camera tracks an object in the scene"), |
||||
("none", "Don't Track", "Camera does not track anything")], |
||||
options=set()) |
||||
poa_object = PointerProperty(name="PoA Object", |
||||
description="Object the camera should track as its Point of Attention", |
||||
type=bpy.types.Object, |
||||
options=set()) |
||||
poa_offset = FloatVectorProperty(name="PoA Offset", |
||||
description="Offset from the point of attention's origin to track", |
||||
soft_min=-50.0, soft_max=50.0, |
||||
size=3, default=(0.0, 0.0, 3.0), |
||||
options=set()) |
||||
poa_worldspace = BoolProperty(name="Worldspace Offset", |
||||
description="Point of Attention Offset is in worldspace coordinates", |
||||
options=set()) |
||||
|
||||
# Position Offset |
||||
pos_offset = FloatVectorProperty(name="Position Offset", |
||||
description="Offset the camera's position", |
||||
soft_min=-50.0, soft_max=50.0, |
||||
size=3, default=(0.0, 10.0, 3.0), |
||||
options=set()) |
||||
pos_worldspace = BoolProperty(name="Worldspace Offset", |
||||
description="Position offset is in worldspace coordinates", |
||||
options=set()) |
||||
|
||||
# Default Transition |
||||
transition = PointerProperty(type=PlasmaTransition, options=set()) |
||||
|
||||
# Limit Panning |
||||
x_pan_angle = FloatProperty(name="X Degrees", |
||||
description="Maximum camera pan angle in the X direction", |
||||
min=0.0, max=math.radians(180.0), precision=0, default=math.radians(90.0), |
||||
subtype="ANGLE", options=set()) |
||||
y_pan_angle = FloatProperty(name="Y Degrees", |
||||
description="Maximum camera pan angle in the Y direction", |
||||
min=0.0, max=math.radians(180.0), precision=0, default=math.radians(90.0), |
||||
subtype="ANGLE", options=set()) |
||||
pan_rate = FloatProperty(name="Pan Velocity", |
||||
description="", |
||||
min=0.0, precision=1, default=50.0, |
||||
unit="VELOCITY", options=set()) |
||||
|
||||
# Zooming |
||||
fov = FloatProperty(name="Default FOV", |
||||
description="Horizontal Field of View angle", |
||||
min=0.0, max=math.radians(180.0), precision=0, default=math.radians(70.0), |
||||
subtype="ANGLE") |
||||
limit_zoom = BoolProperty(name="Limit Zoom", |
||||
description="The camera allows zooming per artist limitations", |
||||
options=set()) |
||||
zoom_max = FloatProperty(name="Max FOV", |
||||
description="Maximum camera FOV when zooming", |
||||
min=0.0, max=math.radians(180.0), precision=0, default=math.radians(120.0), |
||||
subtype="ANGLE", options=set()) |
||||
zoom_min = FloatProperty(name="Min FOV", |
||||
description="Minimum camera FOV when zooming", |
||||
min=0.0, max=math.radians(180.0), precision=0, default=math.radians(35.0), |
||||
subtype="ANGLE", options=set()) |
||||
zoom_rate = FloatProperty(name="Zoom Velocity", |
||||
description="Velocity of the camera's zoom in degrees per second", |
||||
min=0.0, max=180.0, precision=0, default=90.0, |
||||
unit="VELOCITY", options=set()) |
||||
|
||||
# Miscellaneous Movement Props |
||||
maintain_los = BoolProperty(name="Maintain LOS", |
||||
description="The camera should maintain line-of-sight with the object it's tracking", |
||||
options=set()) |
||||
fall_vertical = BoolProperty(name="Fall Camera", |
||||
description="The camera will orient itself vertically when the local player begins falling", |
||||
options=set()) |
||||
fast_run = BoolProperty(name="Faster When Falling", |
||||
description="The camera's velocity will have a floor when the local player is falling", |
||||
options=set()) |
||||
ignore_subworld = BoolProperty(name="Ignore Subworld Movement", |
||||
description="The camera will not be parented to any subworlds", |
||||
options=set()) |
||||
|
||||
# Core Type Properties |
||||
primary_camera = BoolProperty(name="Primary Camera", |
||||
description="The camera should be considered the Age's primary camera.", |
||||
options=set()) |
||||
|
||||
def harvest_actors(self): |
||||
if self.poa_type == "object": |
||||
return set((self.poa_object.name),) |
||||
return set() |
||||
|
||||
|
||||
class PlasmaCamera(bpy.types.PropertyGroup): |
||||
camera_type = EnumProperty(name="Camera Type", |
||||
description="", |
||||
items=camera_types, |
||||
options=set()) |
||||
settings = PointerProperty(type=PlasmaCameraProperties, options=set()) |
||||
transitions = CollectionProperty(type=PlasmaTransition, |
||||
name="Transitions", |
||||
description="", |
||||
options=set()) |
@ -0,0 +1,128 @@
|
||||
# This file is part of Korman. |
||||
# |
||||
# Korman is free software: you can redistribute it and/or modify |
||||
# it under the terms of the GNU General Public License as published by |
||||
# the Free Software Foundation, either version 3 of the License, or |
||||
# (at your option) any later version. |
||||
# |
||||
# Korman is distributed in the hope that it will be useful, |
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
# GNU General Public License for more details. |
||||
# |
||||
# You should have received a copy of the GNU General Public License |
||||
# along with Korman. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
import bpy |
||||
|
||||
class CameraButtonsPanel: |
||||
bl_space_type = "PROPERTIES" |
||||
bl_region_type = "WINDOW" |
||||
bl_context = "data" |
||||
|
||||
@classmethod |
||||
def poll(cls, context): |
||||
return (context.camera and context.scene.render.engine == "PLASMA_GAME") |
||||
|
||||
|
||||
class PlasmaCameraPanel(CameraButtonsPanel, bpy.types.Panel): |
||||
bl_label = "Plasma Camera" |
||||
|
||||
def draw(self, context): |
||||
camera = context.camera.plasma_camera |
||||
layout = self.layout |
||||
|
||||
layout.prop(camera, "camera_type") |
||||
layout.separator() |
||||
draw_camera_properties(camera.camera_type, camera.settings, layout, context) |
||||
|
||||
|
||||
class PlasmaCameraTransitionPanel(CameraButtonsPanel, bpy.types.Panel): |
||||
bl_label = "Plasma Transitions" |
||||
|
||||
def draw(self, context): |
||||
pass |
||||
|
||||
|
||||
def draw_camera_properties(cam_type, props, layout, context): |
||||
trans = props.transition |
||||
|
||||
def _draw_gated_prop(layout, props, gate_prop, actual_prop): |
||||
row = layout.row(align=True) |
||||
row.prop(props, gate_prop, text="") |
||||
row = row.row(align=True) |
||||
row.active = getattr(props, gate_prop) |
||||
row.prop(props, actual_prop) |
||||
|
||||
# Point of Attention |
||||
split = layout.split() |
||||
col = split.column() |
||||
col.label("Camera Mode:") |
||||
col = col.column() |
||||
col.alert = cam_type == "follow" and props.poa_type == "none" |
||||
col.prop(props, "poa_type", text="") |
||||
col.alert = False |
||||
row = col.row() |
||||
row.active = props.poa_type == "object" |
||||
row.prop(props, "poa_object", text="") |
||||
col.separator() |
||||
col.prop(props, "primary_camera") |
||||
|
||||
# Miscellaneous |
||||
col = split.column() |
||||
col.label("Tracking Settings:") |
||||
col.prop(props, "maintain_los") |
||||
col.prop(props, "fall_vertical") |
||||
col.prop(props, "fast_run") |
||||
col.prop(props, "ignore_subworld") |
||||
|
||||
# PoA Tracking |
||||
layout.separator() |
||||
split = layout.split() |
||||
col = split.column() |
||||
col.label("Default Tracking Transition:") |
||||
col.prop(trans, "poa_acceleration", text="Acceleration") |
||||
col.prop(trans, "poa_deceleration", text="Deceleration") |
||||
col.prop(trans, "poa_velocity", text="Maximum Velocity") |
||||
col.prop(trans, "poa_cut") |
||||
|
||||
# PoA Offset |
||||
col = split.column() |
||||
col.label("Point of Attention Offset:") |
||||
col.prop(props, "poa_offset", text="") |
||||
col.prop(props, "poa_worldspace") |
||||
|
||||
# Position Tracking (only for follow cams) |
||||
layout.separator() |
||||
split = layout.split() |
||||
col = split.column() |
||||
|
||||
# Position Transitions |
||||
col.label("Default Position Transition:") |
||||
col.prop(trans, "pos_acceleration", text="Acceleration") |
||||
col.prop(trans, "pos_deceleration", text="Deceleration") |
||||
col.prop(trans, "pos_velocity", text="Maximum Velocity") |
||||
col.prop(trans, "pos_cut") |
||||
|
||||
# Position Offsets |
||||
col = split.column() |
||||
col.active = cam_type == "follow" |
||||
col.label("Position Offset:") |
||||
col.prop(props, "pos_offset", text="") |
||||
col.prop(props, "pos_worldspace") |
||||
|
||||
# Camera Panning |
||||
layout.separator() |
||||
split = layout.split() |
||||
col = split.column() |
||||
col.label("Limit Panning:") |
||||
col.prop(props, "x_pan_angle") |
||||
col.prop(props, "y_pan_angle") |
||||
|
||||
# Camera Zoom |
||||
col = split.column() |
||||
col.label("Field of View:") |
||||
col.prop(props, "fov") |
||||
_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_rate") |
Loading…
Reference in new issue