Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKester Maddock <Christopher.Maddock.1@uni.massey.ac.nz>2004-05-16 16:53:22 +0400
committerKester Maddock <Christopher.Maddock.1@uni.massey.ac.nz>2004-05-16 16:53:22 +0400
commitd162882e3af5fbf53ef90138d2c3521fa0d1a140 (patch)
treed6c77fbca53b6bde439b93913d43d8f01741a34c /source/gameengine/Ketsji/KX_Camera.cpp
parent3b63bbe90c289d139ae8bfddb8f09cf24c5869e4 (diff)
Frustum culling
New Python Hooks for cameras.
Diffstat (limited to 'source/gameengine/Ketsji/KX_Camera.cpp')
-rw-r--r--source/gameengine/Ketsji/KX_Camera.cpp460
1 files changed, 450 insertions, 10 deletions
diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp
index cc970d90339..cad6501bd13 100644
--- a/source/gameengine/Ketsji/KX_Camera.cpp
+++ b/source/gameengine/Ketsji/KX_Camera.cpp
@@ -30,19 +30,25 @@
* ***** END GPL/BL DUAL LICENSE BLOCK *****
* Camera in the gameengine. Cameras are also used for views.
*/
-
+
#include "KX_Camera.h"
+#include "KX_Python.h"
+#include "KX_PyMath.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
KX_Camera::KX_Camera(void* sgReplicationInfo,
SG_Callbacks callbacks,
- const RAS_CameraData& camdata)
+ const RAS_CameraData& camdata,
+ bool frustum_culling)
:
KX_GameObject(sgReplicationInfo,callbacks),
- m_camdata(camdata)
+ m_camdata(camdata),
+ m_dirty(true),
+ m_frustum_culling(frustum_culling),
+ m_set_projection_matrix(false)
{
// setting a name would be nice...
m_name = "cam";
@@ -91,7 +97,7 @@ void KX_Camera::CorrectLookUp(MT_Scalar speed)
-const MT_Point3 KX_Camera::GetCameraLocation()
+const MT_Point3 KX_Camera::GetCameraLocation() const
{
/* this is the camera locatio in cam coords... */
//return m_trans1.getOrigin();
@@ -106,7 +112,7 @@ const MT_Point3 KX_Camera::GetCameraLocation()
/* I want the camera orientation as well. */
-const MT_Quaternion KX_Camera::GetCameraOrientation()
+const MT_Quaternion KX_Camera::GetCameraOrientation() const
{
MT_Transform trans;
trans.setBasis(NodeGetWorldOrientation());
@@ -123,6 +129,8 @@ const MT_Quaternion KX_Camera::GetCameraOrientation()
void KX_Camera::SetProjectionMatrix(const MT_Matrix4x4 & mat)
{
m_projection_matrix = mat;
+ m_dirty = true;
+ m_set_projection_matrix = true;
}
@@ -133,6 +141,7 @@ void KX_Camera::SetProjectionMatrix(const MT_Matrix4x4 & mat)
void KX_Camera::SetModelviewMatrix(const MT_Matrix4x4 & mat)
{
m_modelview_matrix = mat;
+ m_dirty = true;
}
@@ -140,7 +149,7 @@ void KX_Camera::SetModelviewMatrix(const MT_Matrix4x4 & mat)
/**
* Gets the projection matrix that is used by the rasterizer.
*/
-const MT_Matrix4x4& KX_Camera::GetProjectionMatrix()
+const MT_Matrix4x4& KX_Camera::GetProjectionMatrix() const
{
return m_projection_matrix;
}
@@ -150,31 +159,35 @@ const MT_Matrix4x4& KX_Camera::GetProjectionMatrix()
/**
* Gets the modelview matrix that is used by the rasterizer.
*/
-const MT_Matrix4x4& KX_Camera::GetModelviewMatrix()
+const MT_Matrix4x4& KX_Camera::GetModelviewMatrix() const
{
return m_modelview_matrix;
}
+bool KX_Camera::hasValidProjectionMatrix() const
+{
+ return m_set_projection_matrix;
+}
/*
* These getters retrieve the clip data and the focal length
*/
-float KX_Camera::GetLens()
+float KX_Camera::GetLens() const
{
return m_camdata.m_lens;
}
-float KX_Camera::GetCameraNear()
+float KX_Camera::GetCameraNear() const
{
return m_camdata.m_clipstart;
}
-float KX_Camera::GetCameraFar()
+float KX_Camera::GetCameraFar() const
{
return m_camdata.m_clipend;
}
@@ -185,3 +198,430 @@ RAS_CameraData* KX_Camera::GetCameraData()
{
return &m_camdata;
}
+
+void KX_Camera::ExtractClipPlanes()
+{
+ MT_Matrix4x4 m = m_projection_matrix * GetWorldToCamera();
+ // Left clip plane
+ m_planes[0] = m[3] + m[0];
+ // Right clip plane
+ m_planes[1] = m[3] - m[0];
+ // Top clip plane
+ m_planes[2] = m[3] - m[1];
+ // Bottom clip plane
+ m_planes[3] = m[3] + m[1];
+ // Near clip plane
+ m_planes[4] = m[3] + m[2];
+ // Far clip plane
+ m_planes[5] = m[3] - m[2];
+
+ m_dirty = false;
+}
+
+bool KX_Camera::PointInsideFrustum(const MT_Point3& x)
+{
+ if (m_dirty)
+ ExtractClipPlanes();
+
+ for( unsigned int i = 0; i < 6 ; i++ )
+ {
+ if (m_planes[i][0]*x[0] + m_planes[i][1]*x[1] + m_planes[i][2]*x[2] + m_planes[i][3] < 0.)
+ return false;
+ }
+ return true;
+}
+
+int KX_Camera::BoxInsideFrustum(const MT_Point3 *box)
+{
+ if (m_dirty)
+ ExtractClipPlanes();
+
+ unsigned int insideCount = 0;
+ for( unsigned int p = 0; p < 6 ; p++ )
+ {
+ unsigned int behindCount = 0;
+ for (unsigned int v = 0; v < 8 ; v++)
+ {
+ if (m_planes[p][0]*box[v][0] + m_planes[p][1]*box[v][1] + m_planes[p][2]*box[v][2] + m_planes[p][3] < 0.)
+ behindCount++;
+ }
+
+ if (behindCount == 8)
+ return OUTSIDE;
+
+ if (!behindCount)
+ insideCount++;
+ }
+
+ if (insideCount == 6)
+ return INSIDE;
+
+ return INTERSECT;
+}
+
+int KX_Camera::SphereInsideFrustum(const MT_Point3& centre, const MT_Scalar &radius)
+{
+ MT_Scalar distance;
+ for (unsigned int p = 0; p < 6; p++)
+ {
+ distance = m_planes[p][0]*centre[0] + m_planes[p][1]*centre[1] + m_planes[p][2]*centre[2] + m_planes[p][3];
+ if (distance < -radius)
+ return OUTSIDE;
+ if (fabs(distance) < radius)
+ return INTERSECT;
+ }
+ return INSIDE;
+}
+
+bool KX_Camera::GetFrustumCulling() const
+{
+ return m_frustum_culling;
+}
+
+//----------------------------------------------------------------------------
+//Python
+
+
+PyMethodDef KX_Camera::Methods[] = {
+ KX_PYMETHODTABLE(KX_Camera, sphereInsideFrustum),
+ KX_PYMETHODTABLE(KX_Camera, boxInsideFrustum),
+ KX_PYMETHODTABLE(KX_Camera, pointInsideFrustum),
+ KX_PYMETHODTABLE(KX_Camera, getCameraToWorld),
+ KX_PYMETHODTABLE(KX_Camera, getWorldToCamera),
+ KX_PYMETHODTABLE(KX_Camera, getProjectionMatrix),
+ KX_PYMETHODTABLE(KX_Camera, setProjectionMatrix),
+
+ {NULL,NULL} //Sentinel
+};
+
+char KX_Camera::doc[] = "Module KX_Camera\n\n"
+"Constants:\n"
+"\tINSIDE\n"
+"\tINTERSECT\n"
+"\tOUTSIDE\n"
+"Attributes:\n"
+"\tlens -> float\n"
+"\t\tThe camera's lens value\n"
+"\tnear -> float\n"
+"\t\tThe camera's near clip distance\n"
+"\tfar -> float\n"
+"\t\tThe camera's far clip distance\n"
+"\tfrustum_culling -> bool\n"
+"\t\tNon zero if this camera is frustum culling.\n"
+"\tprojection_matrix -> [[float]]\n"
+"\t\tThis camera's projection matrix.\n"
+"\tmodelview_matrix -> [[float]] (read only)\n"
+"\t\tThis camera's model view matrix.\n"
+"\t\tRegenerated every frame from the camera's position and orientation.\n"
+"\tcamera_to_world -> [[float]] (read only)\n"
+"\t\tThis camera's camera to world transform.\n"
+"\t\tRegenerated every frame from the camera's position and orientation.\n"
+"\tworld_to_camera -> [[float]] (read only)\n"
+"\t\tThis camera's world to camera transform.\n"
+"\t\tRegenerated every frame from the camera's position and orientation.\n"
+"\t\tThis is camera_to_world inverted.\n";
+
+PyTypeObject KX_Camera::Type = {
+ PyObject_HEAD_INIT(&PyType_Type)
+ 0,
+ "KX_Camera",
+ sizeof(KX_Camera),
+ 0,
+ PyDestructor,
+ 0,
+ __getattr,
+ __setattr,
+ 0, //&MyPyCompare,
+ __repr,
+ 0, //&cvalue_as_number,
+ 0,
+ 0,
+ 0,
+ 0, 0, 0, 0, 0, 0,
+ doc
+};
+
+PyParentObject KX_Camera::Parents[] = {
+ &KX_Camera::Type,
+ &KX_GameObject::Type,
+ &SCA_IObject::Type,
+ &CValue::Type,
+ NULL
+};
+
+PyObject* KX_Camera::_getattr(const STR_String& attr)
+{
+ if (attr == "INSIDE")
+ return PyInt_FromLong(INSIDE);
+ if (attr == "OUTSIDE")
+ return PyInt_FromLong(OUTSIDE);
+ if (attr == "INTERSECT")
+ return PyInt_FromLong(INTERSECT);
+
+ if (attr == "lens")
+ return PyFloat_FromDouble(GetLens());
+ if (attr == "near")
+ return PyFloat_FromDouble(GetCameraNear());
+ if (attr == "far")
+ return PyFloat_FromDouble(GetCameraFar());
+ if (attr == "frustum_culling")
+ return PyInt_FromLong(m_frustum_culling);
+ if (attr == "projection_matrix")
+ return PyObjectFromMT_Matrix4x4(GetProjectionMatrix());
+ if (attr == "modelview_matrix")
+ return PyObjectFromMT_Matrix4x4(GetModelviewMatrix());
+ if (attr == "camera_to_world")
+ return PyObjectFromMT_Matrix4x4(GetCameraToWorld());
+ if (attr == "world_to_camera")
+ return PyObjectFromMT_Matrix4x4(GetWorldToCamera());
+
+ _getattr_up(KX_GameObject);
+}
+
+int KX_Camera::_setattr(const STR_String &attr, PyObject *pyvalue)
+{
+ if (PyInt_Check(pyvalue))
+ {
+ if (attr == "frustum_culling")
+ {
+ m_frustum_culling = PyInt_AsLong(pyvalue);
+ return 0;
+ }
+ }
+
+ if (PyFloat_Check(pyvalue))
+ {
+ if (attr == "lens")
+ {
+ m_camdata.m_lens = PyFloat_AsDouble(pyvalue);
+ m_set_projection_matrix = false;
+ return 0;
+ }
+ if (attr == "near")
+ {
+ m_camdata.m_clipstart = PyFloat_AsDouble(pyvalue);
+ m_set_projection_matrix = false;
+ return 0;
+ }
+ if (attr == "far")
+ {
+ m_camdata.m_clipend = PyFloat_AsDouble(pyvalue);
+ m_set_projection_matrix = false;
+ return 0;
+ }
+ }
+
+ if (attr == "projection_matrix")
+ {
+ PysetProjectionMatrix((PyObject*) this, pyvalue, NULL);
+ return 0;
+ }
+
+ return KX_GameObject::_setattr(attr, pyvalue);
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, sphereInsideFrustum,
+"sphereInsideFrustum(centre, radius) -> Integer\n"
+"\treturns INSIDE, OUTSIDE or INTERSECT if the given sphere is\n"
+"\tinside/outside/intersects this camera's viewing frustum.\n\n"
+"\tcentre = the centre of the sphere (in world coordinates.)\n"
+"\tradius = the radius of the sphere\n\n"
+"\tExample:\n"
+"\timport GameLogic\n\n"
+"\tco = GameLogic.getCurrentController()\n"
+"\tcam = co.GetOwner()\n\n"
+"\t# A sphere of radius 4.0 located at [x, y, z] = [1.0, 1.0, 1.0]\n"
+"\tif (cam.sphereInsideFrustum([1.0, 1.0, 1.0], 4) != cam.OUTSIDE):\n"
+"\t\t# Sphere is inside frustum !\n"
+"\t\t# Do something useful !\n"
+"\telse:\n"
+"\t\t# Sphere is outside frustum\n"
+)
+{
+ PyObject *pycentre;
+ float radius;
+ if (PyArg_ParseTuple(args, "Of", &pycentre, &radius))
+ {
+ MT_Point3 centre = MT_Point3FromPyList(pycentre);
+ if (PyErr_Occurred())
+ {
+ PyErr_SetString(PyExc_TypeError, "Expected list for argument centre.");
+ return Py_None;
+ }
+
+ return PyInt_FromLong(SphereInsideFrustum(centre, radius));
+ }
+
+ PyErr_SetString(PyExc_TypeError, "Expected arguments: (centre, radius)");
+
+ return Py_None;
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, boxInsideFrustum,
+"boxInsideFrustum(box) -> Integer\n"
+"\treturns INSIDE, OUTSIDE or INTERSECT if the given box is\n"
+"\tinside/outside/intersects this camera's viewing frustum.\n\n"
+"\tbox = a list of the eight (8) corners of the box (in world coordinates.)\n\n"
+"\tExample:\n"
+"\timport GameLogic\n\n"
+"\tco = GameLogic.getCurrentController()\n"
+"\tcam = co.GetOwner()\n\n"
+"\tbox = []\n"
+"\tbox.append([-1.0, -1.0, -1.0])\n"
+"\tbox.append([-1.0, -1.0, 1.0])\n"
+"\tbox.append([-1.0, 1.0, -1.0])\n"
+"\tbox.append([-1.0, 1.0, 1.0])\n"
+"\tbox.append([ 1.0, -1.0, -1.0])\n"
+"\tbox.append([ 1.0, -1.0, 1.0])\n"
+"\tbox.append([ 1.0, 1.0, -1.0])\n"
+"\tbox.append([ 1.0, 1.0, 1.0])\n\n"
+"\tif (cam.boxInsideFrustum(box) != cam.OUTSIDE):\n"
+"\t\t# Box is inside/intersects frustum !\n"
+"\t\t# Do something useful !\n"
+"\telse:\n"
+"\t\t# Box is outside the frustum !\n"
+)
+{
+ PyObject *pybox;
+ if (PyArg_ParseTuple(args, "O", &pybox))
+ {
+ unsigned int num_points = PySequence_Size(pybox);
+ if (num_points != 8)
+ {
+ PyErr_Format(PyExc_TypeError, "Expected eight (8) points, got %d", num_points);
+ return Py_None;
+ }
+
+ MT_Point3 box[8];
+ for (unsigned int p = 0; p < 8 ; p++)
+ {
+ box[p] = MT_Point3FromPyList(PySequence_GetItem(pybox, p));
+ if (PyErr_Occurred())
+ {
+ return Py_None;
+ }
+ }
+
+ return PyInt_FromLong(BoxInsideFrustum(box));
+ }
+
+ PyErr_SetString(PyExc_TypeError, "Expected argument: list of points.");
+
+ return Py_None;
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, pointInsideFrustum,
+"pointInsideFrustum(point) -> Bool\n"
+"\treturns 1 if the given point is inside this camera's viewing frustum.\n\n"
+"\tpoint = The point to test (in world coordinates.)\n\n"
+"\tExample:\n"
+"\timport GameLogic\n\n"
+"\tco = GameLogic.getCurrentController()\n"
+"\tcam = co.GetOwner()\n\n"
+"\t# Test point [0.0, 0.0, 0.0]"
+"\tif (cam.pointInsideFrustum([0.0, 0.0, 0.0])):\n"
+"\t\t# Point is inside frustum !\n"
+"\t\t# Do something useful !\n"
+"\telse:\n"
+"\t\t# Box is outside the frustum !\n"
+)
+{
+ PyObject *pypoint;
+ if (PyArg_ParseTuple(args, "O", &pypoint))
+ {
+ MT_Point3 point = MT_Point3FromPyList(pypoint);
+ if (PyErr_Occurred())
+ return Py_None;
+
+ return PyInt_FromLong(PointInsideFrustum(point));
+ }
+
+ PyErr_SetString(PyExc_TypeError, "Expected point argument.");
+ return Py_None;
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, getCameraToWorld,
+"getCameraToWorld() -> Matrix4x4\n"
+"\treturns the camera to world transformation matrix, as a list of four lists of four values.\n\n"
+"\tie: [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])\n"
+)
+{
+ return PyObjectFromMT_Matrix4x4(GetCameraToWorld());
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, getWorldToCamera,
+"getWorldToCamera() -> Matrix4x4\n"
+"\treturns the world to camera transformation matrix, as a list of four lists of four values.\n\n"
+"\tie: [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])\n"
+)
+{
+ return PyObjectFromMT_Matrix4x4(GetWorldToCamera());
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, getProjectionMatrix,
+"getProjectionMatrix() -> Matrix4x4\n"
+"\treturns this camera's projection matrix, as a list of four lists of four values.\n\n"
+"\tie: [[1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 1.0, 0.0], [0.0, 0.0, 0.0, 1.0]])\n"
+)
+{
+ return PyObjectFromMT_Matrix4x4(GetProjectionMatrix());
+}
+
+KX_PYMETHODDEF_DOC(KX_Camera, setProjectionMatrix,
+"setProjectionMatrix(MT_Matrix4x4 m) -> None\n"
+"\tSets this camera's projection matrix\n"
+"\n"
+"\tExample:\n"
+"\timport GameLogic\n"
+"\t# Set a perspective projection matrix\n"
+"\tdef Perspective(left, right, bottom, top, near, far):\n"
+"\t\tm = MT_Matrix4x4()\n"
+"\t\tm[0][0] = m[0][2] = right - left\n"
+"\t\tm[1][1] = m[1][2] = top - bottom\n"
+"\t\tm[2][2] = m[2][3] = -far - near\n"
+"\t\tm[3][2] = -1\n"
+"\t\tm[3][3] = 0\n"
+"\t\treturn m\n"
+"\n"
+"\t# Set an orthographic projection matrix\n"
+"\tdef Orthographic(left, right, bottom, top, near, far):\n"
+"\t\tm = MT_Matrix4x4()\n"
+"\t\tm[0][0] = right - left\n"
+"\t\tm[0][3] = -right - left\n"
+"\t\tm[1][1] = top - bottom\n"
+"\t\tm[1][3] = -top - bottom\n"
+"\t\tm[2][2] = far - near\n"
+"\t\tm[2][3] = -far - near\n"
+"\t\tm[3][3] = 1\n"
+"\t\treturn m\n"
+"\n"
+"\t# Set an isometric projection matrix\n"
+"\tdef Isometric(left, right, bottom, top, near, far):\n"
+"\t\tm = MT_Matrix4x4()\n"
+"\t\tm[0][0] = m[0][2] = m[1][1] = 0.8660254037844386\n"
+"\t\tm[1][0] = 0.25\n"
+"\t\tm[1][2] = -0.25\n"
+"\t\tm[3][3] = 1\n"
+"\t\treturn m\n"
+"\n"
+"\t"
+"\tco = GameLogic.getCurrentController()\n"
+"\tcam = co.getOwner()\n"
+"\tcam.setProjectionMatrix(Perspective(-1.0, 1.0, -1.0, 1.0, 0.1, 1))\n")
+{
+ PyObject *pymat;
+ if (PyArg_ParseTuple(args, "O", &pymat))
+ {
+ MT_Matrix4x4 mat = MT_Matrix4x4FromPyObject(pymat);
+ if (PyErr_Occurred())
+ {
+ return Py_None;
+ }
+
+ SetProjectionMatrix(mat);
+ return Py_None;
+ }
+
+ PyErr_SetString(PyExc_TypeError, "Expected 4x4 list as matrix argument.");
+ return Py_None;
+}