Fix 73841 : Game Engine - Camera Lens Shift

This is essential for video projection, and the alternative until now was to manually change the projection matrix via Python.
( http://www.blender.org/manual/game_engine/camera/introduction.html#camera-lens-shift
- this page will be removed as soon as I commit this)

Also this is working for perspective and orto cameras BUT if the sensor is not AUTO it will only look correct in blenderplayer (this is an unrelated bug, but just in case someone runs into it while testing this, now you know why you got the issue).

Kudos for the BlenderVR project for supporting this feature development.

Differential Revision: https://developer.blender.org/D1379
This commit is contained in:
Dalai Felinto 2015-06-29 10:45:27 -03:00
parent 3d12d4b94f
commit f12b1790a0
8 changed files with 83 additions and 14 deletions

@ -1461,7 +1461,7 @@ static KX_LightObject *gamelight_from_blamp(Object *ob, Lamp *la, unsigned int l
static KX_Camera *gamecamera_from_bcamera(Object *ob, KX_Scene *kxscene, KX_BlenderSceneConverter *converter) static KX_Camera *gamecamera_from_bcamera(Object *ob, KX_Scene *kxscene, KX_BlenderSceneConverter *converter)
{ {
Camera* ca = static_cast<Camera*>(ob->data); Camera* ca = static_cast<Camera*>(ob->data);
RAS_CameraData camdata(ca->lens, ca->ortho_scale, ca->sensor_x, ca->sensor_y, ca->sensor_fit, ca->clipsta, ca->clipend, ca->type == CAM_PERSP, ca->YF_dofdist); RAS_CameraData camdata(ca->lens, ca->ortho_scale, ca->sensor_x, ca->sensor_y, ca->sensor_fit, ca->shiftx, ca->shifty, ca->clipsta, ca->clipend, ca->type == CAM_PERSP, ca->YF_dofdist);
KX_Camera *gamecamera; KX_Camera *gamecamera;
gamecamera= new KX_Camera(kxscene, KX_Scene::m_callbacks, camdata); gamecamera= new KX_Camera(kxscene, KX_Scene::m_callbacks, camdata);

@ -224,6 +224,22 @@ short KX_Camera::GetSensorFit() const
return m_camdata.m_sensor_fit; return m_camdata.m_sensor_fit;
} }
/**
* Gets the horizontal shift of the sensor - for camera matching.
*/
float KX_Camera::GetShiftHorizontal() const
{
return m_camdata.m_shift_x;
}
/**
* Gets the vertical shift of the sensor - for camera matching.
*/
float KX_Camera::GetShiftVertical() const
{
return m_camdata.m_shift_y;
}
float KX_Camera::GetCameraNear() const float KX_Camera::GetCameraNear() const
{ {
return m_camdata.m_clipstart; return m_camdata.m_clipstart;

@ -206,6 +206,10 @@ public:
float GetSensorHeight() const; float GetSensorHeight() const;
/** Gets the mode FOV is calculating from sensor dimensions */ /** Gets the mode FOV is calculating from sensor dimensions */
short GetSensorFit() const; short GetSensorFit() const;
/** Gets the horizontal shift of the sensor - for camera matching */
float GetShiftHorizontal() const;
/** Gets the vertical shift of the sensor - for camera matching */
float GetShiftVertical() const;
/** Gets the near clip distance. */ /** Gets the near clip distance. */
float GetCameraNear() const; float GetCameraNear() const;
/** Gets the far clip distance. */ /** Gets the far clip distance. */

@ -1159,6 +1159,8 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
nearfrust, nearfrust,
farfrust, farfrust,
cam->GetSensorFit(), cam->GetSensorFit(),
cam->GetShiftHorizontal(),
cam->GetShiftVertical(),
frustum frustum
); );
if (!cam->GetViewport()) { if (!cam->GetViewport()) {
@ -1179,6 +1181,8 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
cam->GetSensorWidth(), cam->GetSensorWidth(),
cam->GetSensorHeight(), cam->GetSensorHeight(),
cam->GetSensorFit(), cam->GetSensorFit(),
cam->GetShiftHorizontal(),
cam->GetShiftVertical(),
nearfrust, nearfrust,
farfrust, farfrust,
frustum frustum

@ -39,6 +39,8 @@ struct RAS_CameraData
float m_sensor_x; float m_sensor_x;
float m_sensor_y; float m_sensor_y;
short m_sensor_fit; short m_sensor_fit;
float m_shift_x;
float m_shift_y;
float m_clipstart; float m_clipstart;
float m_clipend; float m_clipend;
bool m_perspective; bool m_perspective;
@ -50,6 +52,7 @@ struct RAS_CameraData
float m_focallength; float m_focallength;
RAS_CameraData(float lens = 35.0, float scale = 6.0, float sensor_x = 32.0, float sensor_y = 18.0, short sensor_fit = 0, RAS_CameraData(float lens = 35.0, float scale = 6.0, float sensor_x = 32.0, float sensor_y = 18.0, short sensor_fit = 0,
float shift_x = 0.0, float shift_y = 0.0,
float clipstart = 0.1, float clipend = 5000.0, bool perspective = true, float clipstart = 0.1, float clipend = 5000.0, bool perspective = true,
float focallength = 3.0, bool viewport = false, int viewportleft = 0, int viewportbottom = 0, float focallength = 3.0, bool viewport = false, int viewportleft = 0, int viewportbottom = 0,
int viewportright = 0, int viewporttop = 0) : int viewportright = 0, int viewporttop = 0) :
@ -58,6 +61,8 @@ struct RAS_CameraData
m_sensor_x(sensor_x), m_sensor_x(sensor_x),
m_sensor_y(sensor_y), m_sensor_y(sensor_y),
m_sensor_fit(sensor_fit), m_sensor_fit(sensor_fit),
m_shift_x(shift_x),
m_shift_y(shift_y),
m_clipstart(clipstart), m_clipstart(clipstart),
m_clipend(clipend), m_clipend(clipend),
m_perspective(perspective), m_perspective(perspective),

@ -41,15 +41,21 @@ ComputeDefaultFrustum(
const float lens, const float lens,
const float sensor_x, const float sensor_y, const float sensor_x, const float sensor_y,
const short sensor_fit, const short sensor_fit,
const float shift_x,
const float shift_y,
const float design_aspect_ratio, const float design_aspect_ratio,
RAS_FrameFrustum & frustum RAS_FrameFrustum & frustum
) { ) {
float size;
float halfSize; float halfSize;
float sizeX; float sizeX;
float sizeY; float sizeY;
float offsetX;
float offsetY;
if (sensor_fit==RAS_SENSORFIT_AUTO) { if (sensor_fit==RAS_SENSORFIT_AUTO) {
halfSize = (sensor_x / 2.f) * camnear / lens; size = sensor_x * camnear / lens;
halfSize = size * 0.5f;
if (design_aspect_ratio > 1.f) { if (design_aspect_ratio > 1.f) {
// halfsize defines the width // halfsize defines the width
@ -62,20 +68,25 @@ ComputeDefaultFrustum(
} }
} }
else if (sensor_fit==RAS_SENSORFIT_HOR) { else if (sensor_fit==RAS_SENSORFIT_HOR) {
halfSize = (sensor_x / 2.f) * camnear / lens; size = sensor_x * camnear / lens;
halfSize = size * 0.5f;
sizeX = halfSize; sizeX = halfSize;
sizeY = halfSize/design_aspect_ratio; sizeY = halfSize/design_aspect_ratio;
} }
else { else {
halfSize = (sensor_y / 2.f) * camnear / lens; size = sensor_y * camnear / lens;
halfSize = size * 0.5f;
sizeX = halfSize * design_aspect_ratio; sizeX = halfSize * design_aspect_ratio;
sizeY = halfSize; sizeY = halfSize;
} }
frustum.x2 = sizeX; offsetX = size * shift_x;
frustum.x1 = -frustum.x2; offsetY = size * shift_y;
frustum.y2 = sizeY;
frustum.y1 = -frustum.y2; frustum.x2 = sizeX + offsetX;
frustum.x1 = -sizeX + offsetX;
frustum.y2 = sizeY + offsetY;
frustum.y1 = -sizeY + offsetY;
frustum.camnear = camnear; frustum.camnear = camnear;
frustum.camfar = camfar; frustum.camfar = camfar;
} }
@ -88,12 +99,16 @@ ComputeDefaultOrtho(
const float scale, const float scale,
const float design_aspect_ratio, const float design_aspect_ratio,
const short sensor_fit, const short sensor_fit,
const float shift_x,
const float shift_y,
RAS_FrameFrustum & frustum RAS_FrameFrustum & frustum
) )
{ {
float halfSize = scale*0.5f; float halfSize = scale*0.5f;
float sizeX; float sizeX;
float sizeY; float sizeY;
float offsetX;
float offsetY;
if (sensor_fit==RAS_SENSORFIT_AUTO) { if (sensor_fit==RAS_SENSORFIT_AUTO) {
if (design_aspect_ratio > 1.f) { if (design_aspect_ratio > 1.f) {
@ -115,10 +130,13 @@ ComputeDefaultOrtho(
sizeY = halfSize; sizeY = halfSize;
} }
frustum.x2 = sizeX; offsetX = scale * shift_x;
frustum.x1 = -frustum.x2; offsetY = scale * shift_y;
frustum.y2 = sizeY;
frustum.y1 = -frustum.y2; frustum.x2 = sizeX + offsetX;
frustum.x1 = -sizeX + offsetX;
frustum.y2 = sizeY + offsetY;
frustum.y1 = -sizeY + offsetY;
frustum.camnear = camnear; frustum.camnear = camnear;
frustum.camfar = camfar; frustum.camfar = camfar;
} }
@ -221,6 +239,8 @@ ComputeFrustum(
const RAS_Rect &viewport, const RAS_Rect &viewport,
const float lens, const float lens,
const float sensor_x, const float sensor_y, const short sensor_fit, const float sensor_x, const float sensor_y, const short sensor_fit,
const float shift_x,
const float shift_y,
const float camnear, const float camnear,
const float camfar, const float camfar,
RAS_FrameFrustum &frustum RAS_FrameFrustum &frustum
@ -249,6 +269,8 @@ ComputeFrustum(
sensor_x, sensor_x,
sensor_y, sensor_y,
sensor_fit, sensor_fit,
shift_x,
shift_y,
design_aspect_ratio, design_aspect_ratio,
frustum frustum
); );
@ -315,6 +337,8 @@ RAS_FramingManager::
const float camnear, const float camnear,
const float camfar, const float camfar,
const short sensor_fit, const short sensor_fit,
const float shift_x,
const float shift_y,
RAS_FrameFrustum &frustum RAS_FrameFrustum &frustum
) )
{ {
@ -340,6 +364,8 @@ RAS_FramingManager::
scale, scale,
design_aspect_ratio, design_aspect_ratio,
sensor_fit, sensor_fit,
shift_x,
shift_y,
frustum frustum
); );

@ -236,6 +236,8 @@ public :
const float camnear, const float camnear,
const float camfar, const float camfar,
const short sensor_fit, const short sensor_fit,
const float shift_x,
const float shift_y,
RAS_FrameFrustum &frustum RAS_FrameFrustum &frustum
); );
@ -247,6 +249,8 @@ public :
const RAS_Rect &viewport, const RAS_Rect &viewport,
const float lens, const float lens,
const float sensor_x, const float sensor_y, const short sensor_fit, const float sensor_x, const float sensor_y, const short sensor_fit,
const float shift_x,
const float shift_y,
const float camnear, const float camnear,
const float camfar, const float camfar,
RAS_FrameFrustum &frustum RAS_FrameFrustum &frustum
@ -260,6 +264,8 @@ public :
const float lens, const float lens,
const float sensor_x, const float sensor_y, const float sensor_x, const float sensor_y,
const short sensor_fit, const short sensor_fit,
const float shift_x,
const float shift_y,
const float design_aspect_ratio, const float design_aspect_ratio,
RAS_FrameFrustum & frustum RAS_FrameFrustum & frustum
); );
@ -272,6 +278,8 @@ public :
const float scale, const float scale,
const float design_aspect_ratio, const float design_aspect_ratio,
const short sensor_fit, const short sensor_fit,
const float shift_x,
const float shift_y,
RAS_FrameFrustum & frustum RAS_FrameFrustum & frustum
); );

@ -240,6 +240,8 @@ void ImageRender::Render()
float lens = m_camera->GetLens(); float lens = m_camera->GetLens();
float sensor_x = m_camera->GetSensorWidth(); float sensor_x = m_camera->GetSensorWidth();
float sensor_y = m_camera->GetSensorHeight(); float sensor_y = m_camera->GetSensorHeight();
float shift_x = m_camera->GetShiftHorizontal();
float shift_y = m_camera->GetShiftVertical();
bool orthographic = !m_camera->GetCameraData()->m_perspective; bool orthographic = !m_camera->GetCameraData()->m_perspective;
float nearfrust = m_camera->GetCameraNear(); float nearfrust = m_camera->GetCameraNear();
float farfrust = m_camera->GetCameraFar(); float farfrust = m_camera->GetCameraFar();
@ -260,6 +262,8 @@ void ImageRender::Render()
m_camera->GetScale(), m_camera->GetScale(),
aspect_ratio, aspect_ratio,
m_camera->GetSensorFit(), m_camera->GetSensorFit(),
shift_x,
shift_y,
frustrum frustrum
); );
@ -274,6 +278,8 @@ void ImageRender::Render()
sensor_x, sensor_x,
sensor_y, sensor_y,
RAS_SENSORFIT_AUTO, RAS_SENSORFIT_AUTO,
shift_x,
shift_y,
aspect_ratio, aspect_ratio,
frustrum); frustrum);