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